[OMP5.2] Initial support for doacross clause.
This commit is contained in:
parent
41a1625e07
commit
085845a2ac
@ -9046,6 +9046,132 @@ public:
|
||||
Expr *getSize() const { return getStmtAs<Expr>(); }
|
||||
};
|
||||
|
||||
/// This represents the 'doacross' clause for the '#pragma omp ordered'
|
||||
/// directive.
|
||||
///
|
||||
/// \code
|
||||
/// #pragma omp ordered doacross(sink: i-1, j-1)
|
||||
/// \endcode
|
||||
/// In this example directive '#pragma omp ordered' with clause 'doacross' with
|
||||
/// a dependence-type 'sink' and loop-iteration vector expressions i-1 and j-1.
|
||||
class OMPDoacrossClause final
|
||||
: public OMPVarListClause<OMPDoacrossClause>,
|
||||
private llvm::TrailingObjects<OMPDoacrossClause, Expr *> {
|
||||
friend class OMPClauseReader;
|
||||
friend OMPVarListClause;
|
||||
friend TrailingObjects;
|
||||
|
||||
/// Dependence type (sink or source).
|
||||
OpenMPDoacrossClauseModifier DepType = OMPC_DOACROSS_unknown;
|
||||
|
||||
/// Dependence type location.
|
||||
SourceLocation DepLoc;
|
||||
|
||||
/// Colon location.
|
||||
SourceLocation ColonLoc;
|
||||
|
||||
/// Number of loops, associated with the doacross clause.
|
||||
unsigned NumLoops = 0;
|
||||
|
||||
/// Build clause with number of expressions \a N.
|
||||
///
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
/// \param N Number of expressions in the clause.
|
||||
/// \param NumLoops Number of loops associated with the clause.
|
||||
OMPDoacrossClause(SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc, unsigned N, unsigned NumLoops)
|
||||
: OMPVarListClause<OMPDoacrossClause>(llvm::omp::OMPC_doacross, StartLoc,
|
||||
LParenLoc, EndLoc, N),
|
||||
NumLoops(NumLoops) {}
|
||||
|
||||
/// Build an empty clause.
|
||||
///
|
||||
/// \param N Number of expressions in the clause.
|
||||
/// \param NumLoops Number of loops associated with the clause.
|
||||
explicit OMPDoacrossClause(unsigned N, unsigned NumLoops)
|
||||
: OMPVarListClause<OMPDoacrossClause>(llvm::omp::OMPC_doacross,
|
||||
SourceLocation(), SourceLocation(),
|
||||
SourceLocation(), N),
|
||||
NumLoops(NumLoops) {}
|
||||
|
||||
/// Set dependence type.
|
||||
void setDependenceType(OpenMPDoacrossClauseModifier M) { DepType = M; }
|
||||
|
||||
/// Set dependence type location.
|
||||
void setDependenceLoc(SourceLocation Loc) { DepLoc = Loc; }
|
||||
|
||||
/// Set colon location.
|
||||
void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; }
|
||||
|
||||
public:
|
||||
/// Creates clause with a list of expressions \a VL.
|
||||
///
|
||||
/// \param C AST context.
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
/// \param DepType The dependence type.
|
||||
/// \param DepLoc Location of the dependence type.
|
||||
/// \param ColonLoc Location of ':'.
|
||||
/// \param VL List of references to the expressions.
|
||||
/// \param NumLoops Number of loops that associated with the clause.
|
||||
static OMPDoacrossClause *
|
||||
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc, OpenMPDoacrossClauseModifier DepType,
|
||||
SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL,
|
||||
unsigned NumLoops);
|
||||
|
||||
/// Creates an empty clause with \a N expressions.
|
||||
///
|
||||
/// \param C AST context.
|
||||
/// \param N The number of expressions.
|
||||
/// \param NumLoops Number of loops that is associated with this clause.
|
||||
static OMPDoacrossClause *CreateEmpty(const ASTContext &C, unsigned N,
|
||||
unsigned NumLoops);
|
||||
|
||||
/// Get dependence type.
|
||||
OpenMPDoacrossClauseModifier getDependenceType() const { return DepType; }
|
||||
|
||||
/// Get dependence type location.
|
||||
SourceLocation getDependenceLoc() const { return DepLoc; }
|
||||
|
||||
/// Get colon location.
|
||||
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||
|
||||
/// Get number of loops associated with the clause.
|
||||
unsigned getNumLoops() const { return NumLoops; }
|
||||
|
||||
/// Set the loop data.
|
||||
void setLoopData(unsigned NumLoop, Expr *Cnt);
|
||||
|
||||
/// Get the loop data.
|
||||
Expr *getLoopData(unsigned NumLoop);
|
||||
const Expr *getLoopData(unsigned NumLoop) const;
|
||||
|
||||
child_range children() {
|
||||
return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
|
||||
reinterpret_cast<Stmt **>(varlist_end()));
|
||||
}
|
||||
|
||||
const_child_range children() const {
|
||||
auto Children = const_cast<OMPDoacrossClause *>(this)->children();
|
||||
return const_child_range(Children.begin(), Children.end());
|
||||
}
|
||||
|
||||
child_range used_children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range used_children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
|
||||
static bool classof(const OMPClause *T) {
|
||||
return T->getClauseKind() == llvm::omp::OMPC_doacross;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_OPENMPCLAUSE_H
|
||||
|
||||
@ -3864,6 +3864,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPXDynCGroupMemClause(
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPDoacrossClause(
|
||||
OMPDoacrossClause *C) {
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: look at the following tricky-seeming exprs to see if we
|
||||
// need to recurse on anything. These are ones that have methods
|
||||
// returning decls or qualtypes or nestednamespecifier -- though I'm
|
||||
|
||||
@ -10868,7 +10868,7 @@ def note_omp_previous_named_if_clause : Note<
|
||||
def err_omp_ordered_directive_with_param : Error<
|
||||
"'ordered' directive %select{without any clauses|with 'threads' clause}0 cannot be closely nested inside ordered region with specified parameter">;
|
||||
def err_omp_ordered_directive_without_param : Error<
|
||||
"'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter">;
|
||||
"'ordered' directive with '%0' clause cannot be closely nested inside ordered region without specified parameter">;
|
||||
def note_omp_ordered_param : Note<
|
||||
"'ordered' clause%select{| with specified parameter}0">;
|
||||
def err_omp_expected_base_var_name : Error<
|
||||
@ -10900,7 +10900,7 @@ def note_omp_critical_hint_here : Note<
|
||||
def note_omp_critical_no_hint : Note<
|
||||
"%select{|previous }0directive with no 'hint' clause specified">;
|
||||
def err_omp_depend_clause_thread_simd : Error<
|
||||
"'depend' clauses cannot be mixed with '%0' clause">;
|
||||
"'%0' clauses cannot be mixed with '%1' clause">;
|
||||
def err_omp_depend_sink_expected_loop_iteration : Error<
|
||||
"expected%select{| %1}0 loop iteration variable">;
|
||||
def err_omp_depend_sink_unexpected_expr : Error<
|
||||
@ -10909,8 +10909,8 @@ def err_omp_depend_sink_expected_plus_minus : Error<
|
||||
"expected '+' or '-' operation">;
|
||||
def err_omp_taskwait_depend_mutexinoutset_not_allowed : Error<
|
||||
"'mutexinoutset' modifier not allowed in 'depend' clause on 'taskwait' directive">;
|
||||
def err_omp_depend_sink_source_not_allowed : Error<
|
||||
"'depend(%select{source|sink:vec}0)' clause%select{|s}0 cannot be mixed with 'depend(%select{sink:vec|source}0)' clause%select{s|}0">;
|
||||
def err_omp_sink_and_source_not_allowed : Error<
|
||||
"'%0(%select{source|sink:vec}1)' clause%select{|s}1 cannot be mixed with '%0(%select{sink:vec|source}1)' clause%select{s|}1">;
|
||||
def err_omp_depend_zero_length_array_section_not_allowed : Error<
|
||||
"zero-length array section is not allowed in 'depend' clause">;
|
||||
def err_omp_depend_sink_source_with_modifier : Error<
|
||||
|
||||
@ -80,6 +80,9 @@
|
||||
#ifndef OPENMP_NUMTASKS_MODIFIER
|
||||
#define OPENMP_NUMTASKS_MODIFIER(Name)
|
||||
#endif
|
||||
#ifndef OPENMP_DOACROSS_MODIFIER
|
||||
#define OPENMP_DOACROSS_MODIFIER(Name)
|
||||
#endif
|
||||
|
||||
// Static attributes for 'schedule' clause.
|
||||
OPENMP_SCHEDULE_KIND(static)
|
||||
@ -201,6 +204,10 @@ OPENMP_GRAINSIZE_MODIFIER(strict)
|
||||
// Modifiers for the 'num_tasks' clause.
|
||||
OPENMP_NUMTASKS_MODIFIER(strict)
|
||||
|
||||
// Modifiers for the 'doacross' clause.
|
||||
OPENMP_DOACROSS_MODIFIER(source)
|
||||
OPENMP_DOACROSS_MODIFIER(sink)
|
||||
|
||||
#undef OPENMP_NUMTASKS_MODIFIER
|
||||
#undef OPENMP_GRAINSIZE_MODIFIER
|
||||
#undef OPENMP_BIND_KIND
|
||||
@ -224,4 +231,5 @@ OPENMP_NUMTASKS_MODIFIER(strict)
|
||||
#undef OPENMP_DIST_SCHEDULE_KIND
|
||||
#undef OPENMP_DEFAULTMAP_KIND
|
||||
#undef OPENMP_DEFAULTMAP_MODIFIER
|
||||
#undef OPENMP_DOACROSS_MODIFIER
|
||||
|
||||
|
||||
@ -215,6 +215,13 @@ enum OpenMPNumTasksClauseModifier {
|
||||
OMPC_NUMTASKS_unknown
|
||||
};
|
||||
|
||||
/// OpenMP dependence types for 'doacross' clause.
|
||||
enum OpenMPDoacrossClauseModifier {
|
||||
#define OPENMP_DOACROSS_MODIFIER(Name) OMPC_DOACROSS_##Name,
|
||||
#include "clang/Basic/OpenMPKinds.def"
|
||||
OMPC_DOACROSS_unknown
|
||||
};
|
||||
|
||||
/// Contains 'interop' data for 'append_args' and 'init' clauses.
|
||||
class Expr;
|
||||
struct OMPInteropInfo final {
|
||||
|
||||
@ -11032,10 +11032,7 @@ private:
|
||||
/// Initialization of data-sharing attributes stack.
|
||||
void InitDataSharingAttributesStack();
|
||||
void DestroyDataSharingAttributesStack();
|
||||
ExprResult
|
||||
VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind,
|
||||
bool StrictlyPositive = true,
|
||||
bool SuppressExprDiags = false);
|
||||
|
||||
/// Returns OpenMP nesting level for current directive.
|
||||
unsigned getOpenMPNestingLevel() const;
|
||||
|
||||
@ -11121,6 +11118,11 @@ public:
|
||||
return !OMPDeclareVariantScopes.empty();
|
||||
}
|
||||
|
||||
ExprResult
|
||||
VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind,
|
||||
bool StrictlyPositive = true,
|
||||
bool SuppressExprDiags = false);
|
||||
|
||||
/// Given the potential call expression \p Call, determine if there is a
|
||||
/// specialization via the OpenMP declare variant mechanism available. If
|
||||
/// there is, return the specialized call expression, otherwise return the
|
||||
@ -12281,6 +12283,13 @@ public:
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc);
|
||||
|
||||
/// Called on well-formed 'doacross' clause.
|
||||
OMPClause *
|
||||
ActOnOpenMPDoacrossClause(OpenMPDoacrossClauseModifier DepType,
|
||||
SourceLocation DepLoc, SourceLocation ColonLoc,
|
||||
ArrayRef<Expr *> VarList, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc, SourceLocation EndLoc);
|
||||
|
||||
/// The kind of conversion being performed.
|
||||
enum CheckedConversionKind {
|
||||
/// An implicit conversion.
|
||||
|
||||
@ -1669,6 +1669,52 @@ OMPBindClause::Create(const ASTContext &C, OpenMPBindClauseKind K,
|
||||
OMPBindClause *OMPBindClause::CreateEmpty(const ASTContext &C) {
|
||||
return new (C) OMPBindClause();
|
||||
}
|
||||
|
||||
OMPDoacrossClause *
|
||||
OMPDoacrossClause::Create(const ASTContext &C, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc, SourceLocation EndLoc,
|
||||
OpenMPDoacrossClauseModifier DepType,
|
||||
SourceLocation DepLoc, SourceLocation ColonLoc,
|
||||
ArrayRef<Expr *> VL, unsigned NumLoops) {
|
||||
void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(VL.size() + NumLoops),
|
||||
alignof(OMPDoacrossClause));
|
||||
OMPDoacrossClause *Clause = new (Mem)
|
||||
OMPDoacrossClause(StartLoc, LParenLoc, EndLoc, VL.size(), NumLoops);
|
||||
Clause->setDependenceType(DepType);
|
||||
Clause->setDependenceLoc(DepLoc);
|
||||
Clause->setColonLoc(ColonLoc);
|
||||
Clause->setVarRefs(VL);
|
||||
for (unsigned I = 0; I < NumLoops; ++I)
|
||||
Clause->setLoopData(I, nullptr);
|
||||
return Clause;
|
||||
}
|
||||
|
||||
OMPDoacrossClause *OMPDoacrossClause::CreateEmpty(const ASTContext &C,
|
||||
unsigned N,
|
||||
unsigned NumLoops) {
|
||||
void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(N + NumLoops),
|
||||
alignof(OMPDoacrossClause));
|
||||
return new (Mem) OMPDoacrossClause(N, NumLoops);
|
||||
}
|
||||
|
||||
void OMPDoacrossClause::setLoopData(unsigned NumLoop, Expr *Cnt) {
|
||||
assert(NumLoop < NumLoops && "Loop index must be less number of loops.");
|
||||
auto *It = std::next(getVarRefs().end(), NumLoop);
|
||||
*It = Cnt;
|
||||
}
|
||||
|
||||
Expr *OMPDoacrossClause::getLoopData(unsigned NumLoop) {
|
||||
assert(NumLoop < NumLoops && "Loop index must be less number of loops.");
|
||||
auto *It = std::next(getVarRefs().end(), NumLoop);
|
||||
return *It;
|
||||
}
|
||||
|
||||
const Expr *OMPDoacrossClause::getLoopData(unsigned NumLoop) const {
|
||||
assert(NumLoop < NumLoops && "Loop index must be less number of loops.");
|
||||
const auto *It = std::next(getVarRefs().end(), NumLoop);
|
||||
return *It;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OpenMP clauses printing methods
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -2464,6 +2510,14 @@ void OMPClausePrinter::VisitOMPXDynCGroupMemClause(
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
void OMPClausePrinter::VisitOMPDoacrossClause(OMPDoacrossClause *Node) {
|
||||
OS << "doacross(";
|
||||
OpenMPDoacrossClauseModifier DepType = Node->getDependenceType();
|
||||
OS << (DepType == OMPC_DOACROSS_source ? "source:" : "sink:");
|
||||
VisitOMPClauseList(Node, ' ');
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx,
|
||||
VariantMatchInfo &VMI) const {
|
||||
for (const OMPTraitSet &Set : Sets) {
|
||||
|
||||
@ -920,6 +920,9 @@ void OMPClauseProfiler::VisitOMPXDynCGroupMemClause(
|
||||
if (Expr *Size = C->getSize())
|
||||
Profiler->VisitStmt(Size);
|
||||
}
|
||||
void OMPClauseProfiler::VisitOMPDoacrossClause(const OMPDoacrossClause *C) {
|
||||
VisitOMPClauseList(C);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void
|
||||
|
||||
@ -50,6 +50,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str,
|
||||
return OMPC_DEPEND_unknown;
|
||||
return Type;
|
||||
}
|
||||
case OMPC_doacross:
|
||||
return llvm::StringSwitch<OpenMPDoacrossClauseModifier>(Str)
|
||||
#define OPENMP_DOACROSS_MODIFIER(Name) .Case(#Name, OMPC_DOACROSS_##Name)
|
||||
#include "clang/Basic/OpenMPKinds.def"
|
||||
.Default(OMPC_DOACROSS_unknown);
|
||||
case OMPC_linear:
|
||||
return llvm::StringSwitch<OpenMPLinearClauseKind>(Str)
|
||||
#define OPENMP_LINEAR_KIND(Name) .Case(#Name, OMPC_LINEAR_##Name)
|
||||
@ -282,6 +287,16 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
|
||||
#include "clang/Basic/OpenMPKinds.def"
|
||||
}
|
||||
llvm_unreachable("Invalid OpenMP 'depend' clause type");
|
||||
case OMPC_doacross:
|
||||
switch (Type) {
|
||||
case OMPC_DOACROSS_unknown:
|
||||
return "unknown";
|
||||
#define OPENMP_DOACROSS_MODIFIER(Name) \
|
||||
case OMPC_DOACROSS_##Name: \
|
||||
return #Name;
|
||||
#include "clang/Basic/OpenMPKinds.def"
|
||||
}
|
||||
llvm_unreachable("Invalid OpenMP 'doacross' clause type");
|
||||
case OMPC_linear:
|
||||
switch (Type) {
|
||||
case OMPC_LINEAR_unknown:
|
||||
|
||||
@ -2924,17 +2924,20 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
|
||||
// Consume final annot_pragma_openmp_end.
|
||||
ConsumeAnnotationToken();
|
||||
|
||||
// OpenMP [2.13.8, ordered Construct, Syntax]
|
||||
// If the depend clause is specified, the ordered construct is a stand-alone
|
||||
// directive.
|
||||
if (DKind == OMPD_ordered && FirstClauses[unsigned(OMPC_depend)].getInt()) {
|
||||
if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==
|
||||
ParsedStmtContext()) {
|
||||
Diag(Loc, diag::err_omp_immediate_directive)
|
||||
<< getOpenMPDirectiveName(DKind) << 1
|
||||
<< getOpenMPClauseName(OMPC_depend);
|
||||
if (DKind == OMPD_ordered) {
|
||||
// If the depend or doacross clause is specified, the ordered construct
|
||||
// is a stand-alone directive.
|
||||
for (auto CK : {OMPC_depend, OMPC_doacross}) {
|
||||
if (FirstClauses[unsigned(CK)].getInt()) {
|
||||
if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==
|
||||
ParsedStmtContext()) {
|
||||
Diag(Loc, diag::err_omp_immediate_directive)
|
||||
<< getOpenMPDirectiveName(DKind) << 1
|
||||
<< getOpenMPClauseName(CK);
|
||||
}
|
||||
HasAssociatedStatement = false;
|
||||
}
|
||||
}
|
||||
HasAssociatedStatement = false;
|
||||
}
|
||||
|
||||
if (DKind == OMPD_tile && !FirstClauses[unsigned(OMPC_sizes)].getInt()) {
|
||||
@ -3363,6 +3366,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
|
||||
case OMPC_inclusive:
|
||||
case OMPC_exclusive:
|
||||
case OMPC_affinity:
|
||||
case OMPC_doacross:
|
||||
Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective);
|
||||
break;
|
||||
case OMPC_sizes:
|
||||
@ -4366,7 +4370,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
|
||||
if (!InvalidReductionId)
|
||||
Data.ReductionOrMapperId =
|
||||
Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId);
|
||||
} else if (Kind == OMPC_depend) {
|
||||
} else if (Kind == OMPC_depend || Kind == OMPC_doacross) {
|
||||
if (getLangOpts().OpenMP >= 50) {
|
||||
if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") {
|
||||
// Handle optional dependence modifier.
|
||||
@ -4389,13 +4393,16 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
|
||||
Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "",
|
||||
getLangOpts());
|
||||
Data.ExtraModifierLoc = Tok.getLocation();
|
||||
if (Data.ExtraModifier == OMPC_DEPEND_unknown) {
|
||||
if ((Kind == OMPC_depend && Data.ExtraModifier == OMPC_DEPEND_unknown) ||
|
||||
(Kind == OMPC_doacross &&
|
||||
Data.ExtraModifier == OMPC_DOACROSS_unknown)) {
|
||||
SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
|
||||
StopBeforeMatch);
|
||||
} else {
|
||||
ConsumeToken();
|
||||
// Special processing for depend(source) clause.
|
||||
if (DKind == OMPD_ordered && Data.ExtraModifier == OMPC_DEPEND_source) {
|
||||
if (DKind == OMPD_ordered && Kind == OMPC_depend &&
|
||||
Data.ExtraModifier == OMPC_DEPEND_source) {
|
||||
// Parse ')'.
|
||||
T.consumeClose();
|
||||
return false;
|
||||
@ -4406,7 +4413,13 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
|
||||
} else {
|
||||
Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren
|
||||
: diag::warn_pragma_expected_colon)
|
||||
<< "dependency type";
|
||||
<< (Kind == OMPC_depend ? "dependency type" : "dependence-type");
|
||||
}
|
||||
// Special processing for doacross(source) clause.
|
||||
if (Kind == OMPC_doacross && Data.ExtraModifier == OMPC_DOACROSS_source) {
|
||||
// Parse ')'.
|
||||
T.consumeClose();
|
||||
return false;
|
||||
}
|
||||
} else if (Kind == OMPC_linear) {
|
||||
// Try to parse modifier if any.
|
||||
@ -4585,10 +4598,12 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
|
||||
|
||||
bool IsComma =
|
||||
(Kind != OMPC_reduction && Kind != OMPC_task_reduction &&
|
||||
Kind != OMPC_in_reduction && Kind != OMPC_depend && Kind != OMPC_map) ||
|
||||
Kind != OMPC_in_reduction && Kind != OMPC_depend &&
|
||||
Kind != OMPC_doacross && Kind != OMPC_map) ||
|
||||
(Kind == OMPC_reduction && !InvalidReductionId) ||
|
||||
(Kind == OMPC_map && Data.ExtraModifier != OMPC_MAP_unknown) ||
|
||||
(Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown) ||
|
||||
(Kind == OMPC_doacross && Data.ExtraModifier != OMPC_DOACROSS_unknown) ||
|
||||
(Kind == OMPC_adjust_args &&
|
||||
Data.ExtraModifier != OMPC_ADJUST_ARGS_unknown);
|
||||
const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);
|
||||
@ -4646,7 +4661,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
|
||||
// Exit from scope when the iterator is used in depend clause.
|
||||
if (HasIterator)
|
||||
ExitScope();
|
||||
return (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) ||
|
||||
return (Kind != OMPC_depend && Kind != OMPC_doacross && Kind != OMPC_map &&
|
||||
Vars.empty()) ||
|
||||
(MustHaveTail && !Data.DepModOrTailExpr) || InvalidReductionId ||
|
||||
IsInvalidMapperModifier || InvalidIterator;
|
||||
}
|
||||
|
||||
@ -88,8 +88,7 @@ public:
|
||||
};
|
||||
using OperatorOffsetTy =
|
||||
llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>;
|
||||
using DoacrossDependMapTy =
|
||||
llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>;
|
||||
using DoacrossClauseMapTy = llvm::DenseMap<OMPClause *, OperatorOffsetTy>;
|
||||
/// Kind of the declaration used in the uses_allocators clauses.
|
||||
enum class UsesAllocatorsDeclKind {
|
||||
/// Predefined allocator
|
||||
@ -170,7 +169,7 @@ private:
|
||||
/// Set of 'depend' clauses with 'sink|source' dependence kind. Required to
|
||||
/// get the data (loop counters etc.) about enclosing loop-based construct.
|
||||
/// This data is required during codegen.
|
||||
DoacrossDependMapTy DoacrossDepends;
|
||||
DoacrossClauseMapTy DoacrossDepends;
|
||||
/// First argument (Expr *) contains optional argument of the
|
||||
/// 'ordered' clause, the second one is true if the regions has 'ordered'
|
||||
/// clause, false otherwise.
|
||||
@ -1055,17 +1054,16 @@ public:
|
||||
assert(!isStackEmpty());
|
||||
return getStackSize() - 1;
|
||||
}
|
||||
void addDoacrossDependClause(OMPDependClause *C,
|
||||
const OperatorOffsetTy &OpsOffs) {
|
||||
void addDoacrossDependClause(OMPClause *C, const OperatorOffsetTy &OpsOffs) {
|
||||
SharingMapTy *Parent = getSecondOnStackOrNull();
|
||||
assert(Parent && isOpenMPWorksharingDirective(Parent->Directive));
|
||||
Parent->DoacrossDepends.try_emplace(C, OpsOffs);
|
||||
}
|
||||
llvm::iterator_range<DoacrossDependMapTy::const_iterator>
|
||||
llvm::iterator_range<DoacrossClauseMapTy::const_iterator>
|
||||
getDoacrossDependClauses() const {
|
||||
const SharingMapTy &StackElem = getTopOfStack();
|
||||
if (isOpenMPWorksharingDirective(StackElem.Directive)) {
|
||||
const DoacrossDependMapTy &Ref = StackElem.DoacrossDepends;
|
||||
const DoacrossClauseMapTy &Ref = StackElem.DoacrossDepends;
|
||||
return llvm::make_range(Ref.begin(), Ref.end());
|
||||
}
|
||||
return llvm::make_range(StackElem.DoacrossDepends.end(),
|
||||
@ -9335,30 +9333,45 @@ static bool checkOpenMPIterationSpace(
|
||||
}
|
||||
}
|
||||
for (auto &Pair : DSA.getDoacrossDependClauses()) {
|
||||
if (CurrentNestedLoopCount >= Pair.first->getNumLoops()) {
|
||||
auto *DependC = dyn_cast<OMPDependClause>(Pair.first);
|
||||
auto *DoacrossC = dyn_cast<OMPDoacrossClause>(Pair.first);
|
||||
unsigned NumLoops =
|
||||
DependC ? DependC->getNumLoops() : DoacrossC->getNumLoops();
|
||||
if (CurrentNestedLoopCount >= NumLoops) {
|
||||
// Erroneous case - clause has some problems.
|
||||
continue;
|
||||
}
|
||||
if (Pair.first->getDependencyKind() == OMPC_DEPEND_sink &&
|
||||
if (DependC && DependC->getDependencyKind() == OMPC_DEPEND_sink &&
|
||||
Pair.second.size() <= CurrentNestedLoopCount) {
|
||||
// Erroneous case - clause has some problems.
|
||||
Pair.first->setLoopData(CurrentNestedLoopCount, nullptr);
|
||||
DependC->setLoopData(CurrentNestedLoopCount, nullptr);
|
||||
continue;
|
||||
}
|
||||
if (DoacrossC && DoacrossC->getDependenceType() == OMPC_DOACROSS_sink &&
|
||||
Pair.second.size() <= CurrentNestedLoopCount) {
|
||||
// Erroneous case - clause has some problems.
|
||||
DoacrossC->setLoopData(CurrentNestedLoopCount, nullptr);
|
||||
continue;
|
||||
}
|
||||
Expr *CntValue;
|
||||
if (Pair.first->getDependencyKind() == OMPC_DEPEND_source)
|
||||
SourceLocation DepLoc =
|
||||
DependC ? DependC->getDependencyLoc() : DoacrossC->getDependenceLoc();
|
||||
if ((DependC && DependC->getDependencyKind() == OMPC_DEPEND_source) ||
|
||||
(DoacrossC && DoacrossC->getDependenceType() == OMPC_DOACROSS_source))
|
||||
CntValue = ISC.buildOrderedLoopData(
|
||||
DSA.getCurScope(),
|
||||
ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures,
|
||||
Pair.first->getDependencyLoc());
|
||||
DepLoc);
|
||||
else
|
||||
CntValue = ISC.buildOrderedLoopData(
|
||||
DSA.getCurScope(),
|
||||
ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures,
|
||||
Pair.first->getDependencyLoc(),
|
||||
Pair.second[CurrentNestedLoopCount].first,
|
||||
DepLoc, Pair.second[CurrentNestedLoopCount].first,
|
||||
Pair.second[CurrentNestedLoopCount].second);
|
||||
Pair.first->setLoopData(CurrentNestedLoopCount, CntValue);
|
||||
if (DependC)
|
||||
DependC->setLoopData(CurrentNestedLoopCount, CntValue);
|
||||
else
|
||||
DoacrossC->setLoopData(CurrentNestedLoopCount, CntValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11274,33 +11287,47 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
|
||||
const OMPClause *DependFound = nullptr;
|
||||
const OMPClause *DependSourceClause = nullptr;
|
||||
const OMPClause *DependSinkClause = nullptr;
|
||||
const OMPClause *DoacrossFound = nullptr;
|
||||
const OMPClause *DoacrossSourceClause = nullptr;
|
||||
const OMPClause *DoacrossSinkClause = nullptr;
|
||||
bool ErrorFound = false;
|
||||
const OMPThreadsClause *TC = nullptr;
|
||||
const OMPSIMDClause *SC = nullptr;
|
||||
for (const OMPClause *C : Clauses) {
|
||||
if (auto *DC = dyn_cast<OMPDependClause>(C)) {
|
||||
DependFound = C;
|
||||
if (DC->getDependencyKind() == OMPC_DEPEND_source) {
|
||||
if (DependSourceClause) {
|
||||
auto DOC = dyn_cast<OMPDoacrossClause>(C);
|
||||
auto DC = dyn_cast<OMPDependClause>(C);
|
||||
if (DC || DOC) {
|
||||
DependFound = DC ? C : nullptr;
|
||||
DoacrossFound = DOC ? C : nullptr;
|
||||
if ((DC && DC->getDependencyKind() == OMPC_DEPEND_source) ||
|
||||
(DOC && DOC->getDependenceType() == OMPC_DOACROSS_source)) {
|
||||
if ((DC && DependSourceClause) || (DOC && DoacrossSourceClause)) {
|
||||
Diag(C->getBeginLoc(), diag::err_omp_more_one_clause)
|
||||
<< getOpenMPDirectiveName(OMPD_ordered)
|
||||
<< getOpenMPClauseName(OMPC_depend) << 2;
|
||||
<< getOpenMPClauseName(DC ? OMPC_depend : OMPC_doacross) << 2;
|
||||
ErrorFound = true;
|
||||
} else {
|
||||
DependSourceClause = C;
|
||||
if (DC)
|
||||
DependSourceClause = C;
|
||||
else
|
||||
DoacrossSourceClause = C;
|
||||
}
|
||||
if (DependSinkClause) {
|
||||
Diag(C->getBeginLoc(), diag::err_omp_depend_sink_source_not_allowed)
|
||||
<< 0;
|
||||
if ((DC && DependSinkClause) || (DOC && DoacrossSinkClause)) {
|
||||
Diag(C->getBeginLoc(), diag::err_omp_sink_and_source_not_allowed)
|
||||
<< (DC ? "depend" : "doacross") << 0;
|
||||
ErrorFound = true;
|
||||
}
|
||||
} else if (DC->getDependencyKind() == OMPC_DEPEND_sink) {
|
||||
if (DependSourceClause) {
|
||||
Diag(C->getBeginLoc(), diag::err_omp_depend_sink_source_not_allowed)
|
||||
<< 1;
|
||||
} else if ((DC && DC->getDependencyKind() == OMPC_DEPEND_sink) ||
|
||||
(DOC && DOC->getDependenceType() == OMPC_DOACROSS_sink)) {
|
||||
if (DependSourceClause || DoacrossSourceClause) {
|
||||
Diag(C->getBeginLoc(), diag::err_omp_sink_and_source_not_allowed)
|
||||
<< (DC ? "depend" : "doacross") << 1;
|
||||
ErrorFound = true;
|
||||
}
|
||||
DependSinkClause = C;
|
||||
if (DC)
|
||||
DependSinkClause = C;
|
||||
else
|
||||
DoacrossSinkClause = C;
|
||||
}
|
||||
} else if (C->getClauseKind() == OMPC_threads) {
|
||||
TC = cast<OMPThreadsClause>(C);
|
||||
@ -11316,13 +11343,19 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
|
||||
Diag(StartLoc, diag::err_omp_prohibited_region_simd)
|
||||
<< (LangOpts.OpenMP >= 50 ? 1 : 0);
|
||||
ErrorFound = true;
|
||||
} else if (DependFound && (TC || SC)) {
|
||||
Diag(DependFound->getBeginLoc(), diag::err_omp_depend_clause_thread_simd)
|
||||
} else if ((DependFound || DoacrossFound) && (TC || SC)) {
|
||||
SourceLocation Loc =
|
||||
DependFound ? DependFound->getBeginLoc() : DoacrossFound->getBeginLoc();
|
||||
Diag(Loc, diag::err_omp_depend_clause_thread_simd)
|
||||
<< getOpenMPClauseName(DependFound ? OMPC_depend : OMPC_doacross)
|
||||
<< getOpenMPClauseName(TC ? TC->getClauseKind() : SC->getClauseKind());
|
||||
ErrorFound = true;
|
||||
} else if (DependFound && !DSAStack->getParentOrderedRegionParam().first) {
|
||||
Diag(DependFound->getBeginLoc(),
|
||||
diag::err_omp_ordered_directive_without_param);
|
||||
} else if ((DependFound || DoacrossFound) &&
|
||||
!DSAStack->getParentOrderedRegionParam().first) {
|
||||
SourceLocation Loc =
|
||||
DependFound ? DependFound->getBeginLoc() : DoacrossFound->getBeginLoc();
|
||||
Diag(Loc, diag::err_omp_ordered_directive_without_param)
|
||||
<< getOpenMPClauseName(DependFound ? OMPC_depend : OMPC_doacross);
|
||||
ErrorFound = true;
|
||||
} else if (TC || Clauses.empty()) {
|
||||
if (const Expr *Param = DSAStack->getParentOrderedRegionParam().first) {
|
||||
@ -11333,7 +11366,7 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
|
||||
ErrorFound = true;
|
||||
}
|
||||
}
|
||||
if ((!AStmt && !DependFound) || ErrorFound)
|
||||
if ((!AStmt && !DependFound && !DoacrossFound) || ErrorFound)
|
||||
return StmtError();
|
||||
|
||||
// OpenMP 5.0, 2.17.9, ordered Construct, Restrictions.
|
||||
@ -11341,7 +11374,7 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
|
||||
// within a worksharing-loop, simd, or worksharing-loop SIMD region, a thread
|
||||
// must not execute more than one ordered region corresponding to an ordered
|
||||
// construct without a depend clause.
|
||||
if (!DependFound) {
|
||||
if (!DependFound && !DoacrossFound) {
|
||||
if (DSAStack->doesParentHasOrderedDirective()) {
|
||||
Diag(StartLoc, diag::err_omp_several_directives_in_region) << "ordered";
|
||||
Diag(DSAStack->getParentOrderedDirectiveLoc(),
|
||||
@ -17904,6 +17937,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
|
||||
Res = ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc, EndLoc,
|
||||
Data.DepModOrTailExpr, VarList);
|
||||
break;
|
||||
case OMPC_doacross:
|
||||
Res = ActOnOpenMPDoacrossClause(
|
||||
static_cast<OpenMPDoacrossClauseModifier>(ExtraModifier),
|
||||
ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
|
||||
break;
|
||||
case OMPC_if:
|
||||
case OMPC_depobj:
|
||||
case OMPC_final:
|
||||
@ -20525,6 +20563,135 @@ OMPClause *Sema::ActOnOpenMPDepobjClause(Expr *Depobj, SourceLocation StartLoc,
|
||||
return OMPDepobjClause::Create(Context, StartLoc, LParenLoc, EndLoc, Depobj);
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Utility struct that gathers the related info for doacross clause.
|
||||
struct DoacrossDataInfoTy {
|
||||
// The list of expressions.
|
||||
SmallVector<Expr *, 8> Vars;
|
||||
// The OperatorOffset for doacross loop.
|
||||
DSAStackTy::OperatorOffsetTy OpsOffs;
|
||||
// The depended loop count.
|
||||
llvm::APSInt TotalDepCount;
|
||||
};
|
||||
} // namespace
|
||||
static DoacrossDataInfoTy
|
||||
ProcessOpenMPDoacrossClauseCommon(Sema &SemaRef, bool IsSource,
|
||||
ArrayRef<Expr *> VarList, DSAStackTy *Stack,
|
||||
SourceLocation EndLoc) {
|
||||
|
||||
SmallVector<Expr *, 8> Vars;
|
||||
DSAStackTy::OperatorOffsetTy OpsOffs;
|
||||
llvm::APSInt DepCounter(/*BitWidth=*/32);
|
||||
llvm::APSInt TotalDepCount(/*BitWidth=*/32);
|
||||
|
||||
if (const Expr *OrderedCountExpr =
|
||||
Stack->getParentOrderedRegionParam().first) {
|
||||
TotalDepCount = OrderedCountExpr->EvaluateKnownConstInt(SemaRef.Context);
|
||||
TotalDepCount.setIsUnsigned(/*Val=*/true);
|
||||
}
|
||||
|
||||
for (Expr *RefExpr : VarList) {
|
||||
assert(RefExpr && "NULL expr in OpenMP doacross clause.");
|
||||
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
|
||||
// It will be analyzed later.
|
||||
Vars.push_back(RefExpr);
|
||||
continue;
|
||||
}
|
||||
|
||||
SourceLocation ELoc = RefExpr->getExprLoc();
|
||||
Expr *SimpleExpr = RefExpr->IgnoreParenCasts();
|
||||
if (!IsSource) {
|
||||
if (Stack->getParentOrderedRegionParam().first &&
|
||||
DepCounter >= TotalDepCount) {
|
||||
SemaRef.Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr);
|
||||
continue;
|
||||
}
|
||||
++DepCounter;
|
||||
// OpenMP [2.13.9, Summary]
|
||||
// depend(dependence-type : vec), where dependence-type is:
|
||||
// 'sink' and where vec is the iteration vector, which has the form:
|
||||
// x1 [+- d1], x2 [+- d2 ], . . . , xn [+- dn]
|
||||
// where n is the value specified by the ordered clause in the loop
|
||||
// directive, xi denotes the loop iteration variable of the i-th nested
|
||||
// loop associated with the loop directive, and di is a constant
|
||||
// non-negative integer.
|
||||
if (SemaRef.CurContext->isDependentContext()) {
|
||||
// It will be analyzed later.
|
||||
Vars.push_back(RefExpr);
|
||||
continue;
|
||||
}
|
||||
SimpleExpr = SimpleExpr->IgnoreImplicit();
|
||||
OverloadedOperatorKind OOK = OO_None;
|
||||
SourceLocation OOLoc;
|
||||
Expr *LHS = SimpleExpr;
|
||||
Expr *RHS = nullptr;
|
||||
if (auto *BO = dyn_cast<BinaryOperator>(SimpleExpr)) {
|
||||
OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode());
|
||||
OOLoc = BO->getOperatorLoc();
|
||||
LHS = BO->getLHS()->IgnoreParenImpCasts();
|
||||
RHS = BO->getRHS()->IgnoreParenImpCasts();
|
||||
} else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(SimpleExpr)) {
|
||||
OOK = OCE->getOperator();
|
||||
OOLoc = OCE->getOperatorLoc();
|
||||
LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
|
||||
RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
|
||||
} else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SimpleExpr)) {
|
||||
OOK = MCE->getMethodDecl()
|
||||
->getNameInfo()
|
||||
.getName()
|
||||
.getCXXOverloadedOperator();
|
||||
OOLoc = MCE->getCallee()->getExprLoc();
|
||||
LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts();
|
||||
RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
|
||||
}
|
||||
SourceLocation ELoc;
|
||||
SourceRange ERange;
|
||||
auto Res = getPrivateItem(SemaRef, LHS, ELoc, ERange);
|
||||
if (Res.second) {
|
||||
// It will be analyzed later.
|
||||
Vars.push_back(RefExpr);
|
||||
}
|
||||
ValueDecl *D = Res.first;
|
||||
if (!D)
|
||||
continue;
|
||||
|
||||
if (OOK != OO_Plus && OOK != OO_Minus && (RHS || OOK != OO_None)) {
|
||||
SemaRef.Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus);
|
||||
continue;
|
||||
}
|
||||
if (RHS) {
|
||||
ExprResult RHSRes = SemaRef.VerifyPositiveIntegerConstantInClause(
|
||||
RHS, OMPC_depend, /*StrictlyPositive=*/false);
|
||||
if (RHSRes.isInvalid())
|
||||
continue;
|
||||
}
|
||||
if (!SemaRef.CurContext->isDependentContext() &&
|
||||
Stack->getParentOrderedRegionParam().first &&
|
||||
DepCounter != Stack->isParentLoopControlVariable(D).first) {
|
||||
const ValueDecl *VD =
|
||||
Stack->getParentLoopControlVariable(DepCounter.getZExtValue());
|
||||
if (VD)
|
||||
SemaRef.Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration)
|
||||
<< 1 << VD;
|
||||
else
|
||||
SemaRef.Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration)
|
||||
<< 0;
|
||||
continue;
|
||||
}
|
||||
OpsOffs.emplace_back(RHS, OOK);
|
||||
}
|
||||
Vars.push_back(RefExpr->IgnoreParenImpCasts());
|
||||
}
|
||||
if (!SemaRef.CurContext->isDependentContext() && !IsSource &&
|
||||
TotalDepCount > VarList.size() &&
|
||||
Stack->getParentOrderedRegionParam().first &&
|
||||
Stack->getParentLoopControlVariable(VarList.size() + 1)) {
|
||||
SemaRef.Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration)
|
||||
<< 1 << Stack->getParentLoopControlVariable(VarList.size() + 1);
|
||||
}
|
||||
return {Vars, OpsOffs, TotalDepCount};
|
||||
}
|
||||
|
||||
OMPClause *
|
||||
Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data,
|
||||
Expr *DepModifier, ArrayRef<Expr *> VarList,
|
||||
@ -20579,204 +20746,123 @@ Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data,
|
||||
|
||||
SmallVector<Expr *, 8> Vars;
|
||||
DSAStackTy::OperatorOffsetTy OpsOffs;
|
||||
llvm::APSInt DepCounter(/*BitWidth=*/32);
|
||||
llvm::APSInt TotalDepCount(/*BitWidth=*/32);
|
||||
|
||||
if (DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) {
|
||||
if (const Expr *OrderedCountExpr =
|
||||
DSAStack->getParentOrderedRegionParam().first) {
|
||||
TotalDepCount = OrderedCountExpr->EvaluateKnownConstInt(Context);
|
||||
TotalDepCount.setIsUnsigned(/*Val=*/true);
|
||||
}
|
||||
}
|
||||
for (Expr *RefExpr : VarList) {
|
||||
assert(RefExpr && "NULL expr in OpenMP shared clause.");
|
||||
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
|
||||
// It will be analyzed later.
|
||||
Vars.push_back(RefExpr);
|
||||
continue;
|
||||
}
|
||||
|
||||
SourceLocation ELoc = RefExpr->getExprLoc();
|
||||
Expr *SimpleExpr = RefExpr->IgnoreParenCasts();
|
||||
if (DepKind == OMPC_DEPEND_sink) {
|
||||
if (DSAStack->getParentOrderedRegionParam().first &&
|
||||
DepCounter >= TotalDepCount) {
|
||||
Diag(ELoc, diag::err_omp_depend_sink_unexpected_expr);
|
||||
continue;
|
||||
}
|
||||
++DepCounter;
|
||||
// OpenMP [2.13.9, Summary]
|
||||
// depend(dependence-type : vec), where dependence-type is:
|
||||
// 'sink' and where vec is the iteration vector, which has the form:
|
||||
// x1 [+- d1], x2 [+- d2 ], . . . , xn [+- dn]
|
||||
// where n is the value specified by the ordered clause in the loop
|
||||
// directive, xi denotes the loop iteration variable of the i-th nested
|
||||
// loop associated with the loop directive, and di is a constant
|
||||
// non-negative integer.
|
||||
if (CurContext->isDependentContext()) {
|
||||
DoacrossDataInfoTy VarOffset = ProcessOpenMPDoacrossClauseCommon(
|
||||
*this, DepKind == OMPC_DEPEND_source, VarList, DSAStack, EndLoc);
|
||||
Vars = VarOffset.Vars;
|
||||
OpsOffs = VarOffset.OpsOffs;
|
||||
TotalDepCount = VarOffset.TotalDepCount;
|
||||
} else {
|
||||
for (Expr *RefExpr : VarList) {
|
||||
assert(RefExpr && "NULL expr in OpenMP shared clause.");
|
||||
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
|
||||
// It will be analyzed later.
|
||||
Vars.push_back(RefExpr);
|
||||
continue;
|
||||
}
|
||||
SimpleExpr = SimpleExpr->IgnoreImplicit();
|
||||
OverloadedOperatorKind OOK = OO_None;
|
||||
SourceLocation OOLoc;
|
||||
Expr *LHS = SimpleExpr;
|
||||
Expr *RHS = nullptr;
|
||||
if (auto *BO = dyn_cast<BinaryOperator>(SimpleExpr)) {
|
||||
OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode());
|
||||
OOLoc = BO->getOperatorLoc();
|
||||
LHS = BO->getLHS()->IgnoreParenImpCasts();
|
||||
RHS = BO->getRHS()->IgnoreParenImpCasts();
|
||||
} else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(SimpleExpr)) {
|
||||
OOK = OCE->getOperator();
|
||||
OOLoc = OCE->getOperatorLoc();
|
||||
LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
|
||||
RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
|
||||
} else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SimpleExpr)) {
|
||||
OOK = MCE->getMethodDecl()
|
||||
->getNameInfo()
|
||||
.getName()
|
||||
.getCXXOverloadedOperator();
|
||||
OOLoc = MCE->getCallee()->getExprLoc();
|
||||
LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts();
|
||||
RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
|
||||
}
|
||||
SourceLocation ELoc;
|
||||
SourceRange ERange;
|
||||
auto Res = getPrivateItem(*this, LHS, ELoc, ERange);
|
||||
if (Res.second) {
|
||||
// It will be analyzed later.
|
||||
Vars.push_back(RefExpr);
|
||||
}
|
||||
ValueDecl *D = Res.first;
|
||||
if (!D)
|
||||
continue;
|
||||
|
||||
if (OOK != OO_Plus && OOK != OO_Minus && (RHS || OOK != OO_None)) {
|
||||
Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus);
|
||||
continue;
|
||||
}
|
||||
if (RHS) {
|
||||
ExprResult RHSRes = VerifyPositiveIntegerConstantInClause(
|
||||
RHS, OMPC_depend, /*StrictlyPositive=*/false);
|
||||
if (RHSRes.isInvalid())
|
||||
continue;
|
||||
}
|
||||
if (!CurContext->isDependentContext() &&
|
||||
DSAStack->getParentOrderedRegionParam().first &&
|
||||
DepCounter != DSAStack->isParentLoopControlVariable(D).first) {
|
||||
const ValueDecl *VD =
|
||||
DSAStack->getParentLoopControlVariable(DepCounter.getZExtValue());
|
||||
if (VD)
|
||||
Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration)
|
||||
<< 1 << VD;
|
||||
else
|
||||
Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) << 0;
|
||||
continue;
|
||||
}
|
||||
OpsOffs.emplace_back(RHS, OOK);
|
||||
} else {
|
||||
bool OMPDependTFound = LangOpts.OpenMP >= 50;
|
||||
if (OMPDependTFound)
|
||||
OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack,
|
||||
DepKind == OMPC_DEPEND_depobj);
|
||||
if (DepKind == OMPC_DEPEND_depobj) {
|
||||
// OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++
|
||||
// List items used in depend clauses with the depobj dependence type
|
||||
// must be expressions of the omp_depend_t type.
|
||||
if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() &&
|
||||
!RefExpr->isInstantiationDependent() &&
|
||||
!RefExpr->containsUnexpandedParameterPack() &&
|
||||
(OMPDependTFound &&
|
||||
!Context.hasSameUnqualifiedType(DSAStack->getOMPDependT(),
|
||||
RefExpr->getType()))) {
|
||||
Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue)
|
||||
<< 0 << RefExpr->getType() << RefExpr->getSourceRange();
|
||||
continue;
|
||||
}
|
||||
if (!RefExpr->isLValue()) {
|
||||
Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue)
|
||||
<< 1 << RefExpr->getType() << RefExpr->getSourceRange();
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// OpenMP 5.0 [2.17.11, Restrictions]
|
||||
// List items used in depend clauses cannot be zero-length array
|
||||
// sections.
|
||||
QualType ExprTy = RefExpr->getType().getNonReferenceType();
|
||||
const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
|
||||
if (OASE) {
|
||||
QualType BaseType =
|
||||
OMPArraySectionExpr::getBaseOriginalType(OASE->getBase());
|
||||
if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
|
||||
ExprTy = ATy->getElementType();
|
||||
else
|
||||
ExprTy = BaseType->getPointeeType();
|
||||
ExprTy = ExprTy.getNonReferenceType();
|
||||
const Expr *Length = OASE->getLength();
|
||||
Expr::EvalResult Result;
|
||||
if (Length && !Length->isValueDependent() &&
|
||||
Length->EvaluateAsInt(Result, Context) &&
|
||||
Result.Val.getInt().isZero()) {
|
||||
Diag(ELoc,
|
||||
diag::err_omp_depend_zero_length_array_section_not_allowed)
|
||||
<< SimpleExpr->getSourceRange();
|
||||
SourceLocation ELoc = RefExpr->getExprLoc();
|
||||
Expr *SimpleExpr = RefExpr->IgnoreParenCasts();
|
||||
if (DepKind != OMPC_DEPEND_sink && DepKind != OMPC_DEPEND_source) {
|
||||
bool OMPDependTFound = LangOpts.OpenMP >= 50;
|
||||
if (OMPDependTFound)
|
||||
OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack,
|
||||
DepKind == OMPC_DEPEND_depobj);
|
||||
if (DepKind == OMPC_DEPEND_depobj) {
|
||||
// OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++
|
||||
// List items used in depend clauses with the depobj dependence type
|
||||
// must be expressions of the omp_depend_t type.
|
||||
if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() &&
|
||||
!RefExpr->isInstantiationDependent() &&
|
||||
!RefExpr->containsUnexpandedParameterPack() &&
|
||||
(OMPDependTFound &&
|
||||
!Context.hasSameUnqualifiedType(DSAStack->getOMPDependT(),
|
||||
RefExpr->getType()))) {
|
||||
Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue)
|
||||
<< 0 << RefExpr->getType() << RefExpr->getSourceRange();
|
||||
continue;
|
||||
}
|
||||
if (!RefExpr->isLValue()) {
|
||||
Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue)
|
||||
<< 1 << RefExpr->getType() << RefExpr->getSourceRange();
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// OpenMP 5.0 [2.17.11, Restrictions]
|
||||
// List items used in depend clauses cannot be zero-length array
|
||||
// sections.
|
||||
QualType ExprTy = RefExpr->getType().getNonReferenceType();
|
||||
const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
|
||||
if (OASE) {
|
||||
QualType BaseType =
|
||||
OMPArraySectionExpr::getBaseOriginalType(OASE->getBase());
|
||||
if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
|
||||
ExprTy = ATy->getElementType();
|
||||
else
|
||||
ExprTy = BaseType->getPointeeType();
|
||||
ExprTy = ExprTy.getNonReferenceType();
|
||||
const Expr *Length = OASE->getLength();
|
||||
Expr::EvalResult Result;
|
||||
if (Length && !Length->isValueDependent() &&
|
||||
Length->EvaluateAsInt(Result, Context) &&
|
||||
Result.Val.getInt().isZero()) {
|
||||
Diag(ELoc,
|
||||
diag::err_omp_depend_zero_length_array_section_not_allowed)
|
||||
<< SimpleExpr->getSourceRange();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++
|
||||
// List items used in depend clauses with the in, out, inout,
|
||||
// inoutset, or mutexinoutset dependence types cannot be
|
||||
// expressions of the omp_depend_t type.
|
||||
if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() &&
|
||||
!RefExpr->isInstantiationDependent() &&
|
||||
!RefExpr->containsUnexpandedParameterPack() &&
|
||||
(!RefExpr->IgnoreParenImpCasts()->isLValue() ||
|
||||
(OMPDependTFound && DSAStack->getOMPDependT().getTypePtr() ==
|
||||
ExprTy.getTypePtr()))) {
|
||||
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
|
||||
<< (LangOpts.OpenMP >= 50 ? 1 : 0)
|
||||
<< (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
|
||||
continue;
|
||||
}
|
||||
|
||||
auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
|
||||
if (ASE && !ASE->getBase()->isTypeDependent() &&
|
||||
!ASE->getBase()
|
||||
->getType()
|
||||
.getNonReferenceType()
|
||||
->isPointerType() &&
|
||||
!ASE->getBase()->getType().getNonReferenceType()->isArrayType()) {
|
||||
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
|
||||
<< (LangOpts.OpenMP >= 50 ? 1 : 0)
|
||||
<< (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
|
||||
continue;
|
||||
}
|
||||
|
||||
ExprResult Res;
|
||||
{
|
||||
Sema::TentativeAnalysisScope Trap(*this);
|
||||
Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf,
|
||||
RefExpr->IgnoreParenImpCasts());
|
||||
}
|
||||
if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) &&
|
||||
!isa<OMPArrayShapingExpr>(SimpleExpr)) {
|
||||
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
|
||||
<< (LangOpts.OpenMP >= 50 ? 1 : 0)
|
||||
<< (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++
|
||||
// List items used in depend clauses with the in, out, inout,
|
||||
// inoutset, or mutexinoutset dependence types cannot be
|
||||
// expressions of the omp_depend_t type.
|
||||
if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() &&
|
||||
!RefExpr->isInstantiationDependent() &&
|
||||
!RefExpr->containsUnexpandedParameterPack() &&
|
||||
(!RefExpr->IgnoreParenImpCasts()->isLValue() ||
|
||||
(OMPDependTFound &&
|
||||
DSAStack->getOMPDependT().getTypePtr() == ExprTy.getTypePtr()))) {
|
||||
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
|
||||
<< (LangOpts.OpenMP >= 50 ? 1 : 0)
|
||||
<< (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
|
||||
continue;
|
||||
}
|
||||
|
||||
auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
|
||||
if (ASE && !ASE->getBase()->isTypeDependent() &&
|
||||
!ASE->getBase()->getType().getNonReferenceType()->isPointerType() &&
|
||||
!ASE->getBase()->getType().getNonReferenceType()->isArrayType()) {
|
||||
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
|
||||
<< (LangOpts.OpenMP >= 50 ? 1 : 0)
|
||||
<< (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
|
||||
continue;
|
||||
}
|
||||
|
||||
ExprResult Res;
|
||||
{
|
||||
Sema::TentativeAnalysisScope Trap(*this);
|
||||
Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf,
|
||||
RefExpr->IgnoreParenImpCasts());
|
||||
}
|
||||
if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) &&
|
||||
!isa<OMPArrayShapingExpr>(SimpleExpr)) {
|
||||
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
|
||||
<< (LangOpts.OpenMP >= 50 ? 1 : 0)
|
||||
<< (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Vars.push_back(RefExpr->IgnoreParenImpCasts());
|
||||
}
|
||||
Vars.push_back(RefExpr->IgnoreParenImpCasts());
|
||||
}
|
||||
|
||||
if (!CurContext->isDependentContext() && DepKind == OMPC_DEPEND_sink &&
|
||||
TotalDepCount > VarList.size() &&
|
||||
DSAStack->getParentOrderedRegionParam().first &&
|
||||
DSAStack->getParentLoopControlVariable(VarList.size() + 1)) {
|
||||
Diag(EndLoc, diag::err_omp_depend_sink_expected_loop_iteration)
|
||||
<< 1 << DSAStack->getParentLoopControlVariable(VarList.size() + 1);
|
||||
}
|
||||
if (DepKind != OMPC_DEPEND_source && DepKind != OMPC_DEPEND_sink &&
|
||||
DepKind != OMPC_DEPEND_outallmemory &&
|
||||
DepKind != OMPC_DEPEND_inoutallmemory && Vars.empty())
|
||||
@ -23947,3 +24033,31 @@ OMPClause *Sema::ActOnOpenMPXDynCGroupMemClause(Expr *Size,
|
||||
return new (Context) OMPXDynCGroupMemClause(
|
||||
ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
|
||||
}
|
||||
|
||||
OMPClause *Sema::ActOnOpenMPDoacrossClause(
|
||||
OpenMPDoacrossClauseModifier DepType, SourceLocation DepLoc,
|
||||
SourceLocation ColonLoc, ArrayRef<Expr *> VarList, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc, SourceLocation EndLoc) {
|
||||
|
||||
if (DSAStack->getCurrentDirective() == OMPD_ordered &&
|
||||
DepType != OMPC_DOACROSS_source && DepType != OMPC_DOACROSS_sink) {
|
||||
Diag(DepLoc, diag::err_omp_unexpected_clause_value)
|
||||
<< "'source' or 'sink'" << getOpenMPClauseName(OMPC_doacross);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SmallVector<Expr *, 8> Vars;
|
||||
DSAStackTy::OperatorOffsetTy OpsOffs;
|
||||
llvm::APSInt TotalDepCount(/*BitWidth=*/32);
|
||||
DoacrossDataInfoTy VarOffset = ProcessOpenMPDoacrossClauseCommon(
|
||||
*this, DepType == OMPC_DOACROSS_source, VarList, DSAStack, EndLoc);
|
||||
Vars = VarOffset.Vars;
|
||||
OpsOffs = VarOffset.OpsOffs;
|
||||
TotalDepCount = VarOffset.TotalDepCount;
|
||||
auto *C = OMPDoacrossClause::Create(Context, StartLoc, LParenLoc, EndLoc,
|
||||
DepType, DepLoc, ColonLoc, Vars,
|
||||
TotalDepCount.getZExtValue());
|
||||
if (DSAStack->isParentOrderedRegion())
|
||||
DSAStack->addDoacrossDependClause(C, OpsOffs);
|
||||
return C;
|
||||
}
|
||||
|
||||
@ -2422,6 +2422,19 @@ public:
|
||||
return getSema().ActOnOpenMPMessageClause(MS, StartLoc, LParenLoc, EndLoc);
|
||||
}
|
||||
|
||||
/// Build a new OpenMP 'doacross' clause.
|
||||
///
|
||||
/// By default, performs semantic analysis to build the new OpenMP clause.
|
||||
/// Subclasses may override this routine to provide different behavior.
|
||||
OMPClause *
|
||||
RebuildOMPDoacrossClause(OpenMPDoacrossClauseModifier DepType,
|
||||
SourceLocation DepLoc, SourceLocation ColonLoc,
|
||||
ArrayRef<Expr *> VarList, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc, SourceLocation EndLoc) {
|
||||
return getSema().ActOnOpenMPDoacrossClause(
|
||||
DepType, DepLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
|
||||
}
|
||||
|
||||
/// Rebuild the operand to an Objective-C \@synchronized statement.
|
||||
///
|
||||
/// By default, performs semantic analysis to build the new statement.
|
||||
@ -10727,6 +10740,22 @@ OMPClause *TreeTransform<Derived>::TransformOMPXDynCGroupMemClause(
|
||||
Size.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
OMPClause *
|
||||
TreeTransform<Derived>::TransformOMPDoacrossClause(OMPDoacrossClause *C) {
|
||||
llvm::SmallVector<Expr *, 16> Vars;
|
||||
Vars.reserve(C->varlist_size());
|
||||
for (auto *VE : C->varlists()) {
|
||||
ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
|
||||
if (EVar.isInvalid())
|
||||
return nullptr;
|
||||
Vars.push_back(EVar.get());
|
||||
}
|
||||
return getDerived().RebuildOMPDoacrossClause(
|
||||
C->getDependenceType(), C->getDependenceLoc(), C->getColonLoc(), Vars,
|
||||
C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Expression transformation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -10362,6 +10362,12 @@ OMPClause *OMPClauseReader::readClause() {
|
||||
case llvm::omp::OMPC_ompx_dyn_cgroup_mem:
|
||||
C = new (Context) OMPXDynCGroupMemClause();
|
||||
break;
|
||||
case llvm::omp::OMPC_doacross: {
|
||||
unsigned NumVars = Record.readInt();
|
||||
unsigned NumLoops = Record.readInt();
|
||||
C = OMPDoacrossClause::CreateEmpty(Context, NumVars, NumLoops);
|
||||
break;
|
||||
}
|
||||
#define OMP_CLAUSE_NO_CLASS(Enum, Str) \
|
||||
case llvm::omp::Enum: \
|
||||
break;
|
||||
@ -11438,6 +11444,22 @@ void OMPClauseReader::VisitOMPXDynCGroupMemClause(OMPXDynCGroupMemClause *C) {
|
||||
C->setLParenLoc(Record.readSourceLocation());
|
||||
}
|
||||
|
||||
void OMPClauseReader::VisitOMPDoacrossClause(OMPDoacrossClause *C) {
|
||||
C->setLParenLoc(Record.readSourceLocation());
|
||||
C->setDependenceType(
|
||||
static_cast<OpenMPDoacrossClauseModifier>(Record.readInt()));
|
||||
C->setDependenceLoc(Record.readSourceLocation());
|
||||
C->setColonLoc(Record.readSourceLocation());
|
||||
unsigned NumVars = C->varlist_size();
|
||||
SmallVector<Expr *, 16> Vars;
|
||||
Vars.reserve(NumVars);
|
||||
for (unsigned I = 0; I != NumVars; ++I)
|
||||
Vars.push_back(Record.readSubExpr());
|
||||
C->setVarRefs(Vars);
|
||||
for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I)
|
||||
C->setLoopData(I, Record.readSubExpr());
|
||||
}
|
||||
|
||||
OMPTraitInfo *ASTRecordReader::readOMPTraitInfo() {
|
||||
OMPTraitInfo &TI = getContext().getNewOMPTraitInfo();
|
||||
TI.Sets.resize(readUInt32());
|
||||
|
||||
@ -7155,6 +7155,19 @@ void OMPClauseWriter::VisitOMPXDynCGroupMemClause(OMPXDynCGroupMemClause *C) {
|
||||
Record.AddSourceLocation(C->getLParenLoc());
|
||||
}
|
||||
|
||||
void OMPClauseWriter::VisitOMPDoacrossClause(OMPDoacrossClause *C) {
|
||||
Record.push_back(C->varlist_size());
|
||||
Record.push_back(C->getNumLoops());
|
||||
Record.AddSourceLocation(C->getLParenLoc());
|
||||
Record.push_back(C->getDependenceType());
|
||||
Record.AddSourceLocation(C->getDependenceLoc());
|
||||
Record.AddSourceLocation(C->getColonLoc());
|
||||
for (auto *VE : C->varlists())
|
||||
Record.AddStmt(VE);
|
||||
for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I)
|
||||
Record.AddStmt(C->getLoopData(I));
|
||||
}
|
||||
|
||||
void ASTRecordWriter::writeOMPTraitInfo(const OMPTraitInfo *TI) {
|
||||
writeUInt32(TI->Sets.size());
|
||||
for (const auto &Set : TI->Sets) {
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck -check-prefixes CHECK,OMP51 %s
|
||||
// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
|
||||
// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
|
||||
// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck -check-prefixes CHECK,OMP51 %s
|
||||
|
||||
// RUN: %clang_cc1 -verify -fopenmp-simd -ast-print %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -verify -fopenmp-version=52 -fopenmp -ast-print %s | FileCheck -check-prefixes CHECK,OMP52 %s
|
||||
// RUN: %clang_cc1 -fopenmp -fopenmp-version=52 -x c++ -std=c++11 -emit-pch -o %t %s
|
||||
// RUN: %clang_cc1 -fopenmp -fopenmp-version=52 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck -check-prefixes CHECK,OMP52 %s
|
||||
|
||||
// RUN: %clang_cc1 -verify -fopenmp-simd -ast-print %s | FileCheck -check-prefixes CHECK,OMP51 %s
|
||||
// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -emit-pch -o %t %s
|
||||
// RUN: %clang_cc1 -fopenmp-simd -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
|
||||
// RUN: %clang_cc1 -fopenmp-simd -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck -check-prefixes CHECK,OMP51 %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
#ifndef HEADER
|
||||
@ -48,8 +52,13 @@ T tmain (T argc) {
|
||||
}
|
||||
#pragma omp parallel for ordered(1)
|
||||
for (int i =0 ; i < argc; ++i) {
|
||||
#if _OPENMP >= 202111
|
||||
#pragma omp ordered doacross(source:)
|
||||
#pragma omp ordered doacross(sink:i+N)
|
||||
#else
|
||||
#pragma omp ordered depend(source)
|
||||
#pragma omp ordered depend(sink:i+N)
|
||||
#endif
|
||||
a = 2;
|
||||
}
|
||||
return (0);
|
||||
@ -88,8 +97,13 @@ T tmain (T argc) {
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: #pragma omp parallel for ordered(1)
|
||||
// CHECK-NEXT: for (int i = 0; i < argc; ++i) {
|
||||
// CHECK-NEXT: #pragma omp ordered depend(source)
|
||||
// CHECK-NEXT: #pragma omp ordered depend(sink : i + N)
|
||||
#if _OPENMP >= 202111
|
||||
// OMP52: #pragma omp ordered doacross(source:)
|
||||
// OMP52-NEXT: #pragma omp ordered doacross(sink: i + N)
|
||||
#else
|
||||
// OMP51: #pragma omp ordered depend(source)
|
||||
// OMP51-NEXT: #pragma omp ordered depend(sink : i + N)
|
||||
#endif
|
||||
// CHECK-NEXT: a = 2;
|
||||
// CHECK-NEXT: }
|
||||
// CHECK: static int a;
|
||||
@ -125,8 +139,13 @@ T tmain (T argc) {
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: #pragma omp parallel for ordered(1)
|
||||
// CHECK-NEXT: for (int i = 0; i < argc; ++i) {
|
||||
// CHECK-NEXT: #pragma omp ordered depend(source)
|
||||
// CHECK-NEXT: #pragma omp ordered depend(sink : i + 3)
|
||||
#if _OPENMP >= 202111
|
||||
// OMP52: #pragma omp ordered doacross(source:)
|
||||
// OMP52-NEXT: #pragma omp ordered doacross(sink: i + 3)
|
||||
#else
|
||||
// OMP51: #pragma omp ordered depend(source)
|
||||
// OMP51-NEXT: #pragma omp ordered depend(sink : i + 3)
|
||||
#endif
|
||||
// CHECK-NEXT: a = 2;
|
||||
// CHECK-NEXT: }
|
||||
|
||||
@ -167,8 +186,13 @@ int main (int argc, char **argv) {
|
||||
}
|
||||
#pragma omp parallel for ordered(1)
|
||||
for (int i =0 ; i < argc; ++i) {
|
||||
#if _OPENMP >= 202111
|
||||
#pragma omp ordered doacross(source:)
|
||||
#pragma omp ordered doacross(sink: i - 5)
|
||||
#else
|
||||
#pragma omp ordered depend(source)
|
||||
#pragma omp ordered depend(sink: i - 5)
|
||||
#endif
|
||||
a = 2;
|
||||
}
|
||||
// CHECK-NEXT: #pragma omp for ordered
|
||||
@ -203,8 +227,13 @@ int main (int argc, char **argv) {
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: #pragma omp parallel for ordered(1)
|
||||
// CHECK-NEXT: for (int i = 0; i < argc; ++i) {
|
||||
// CHECK-NEXT: #pragma omp ordered depend(source)
|
||||
// CHECK-NEXT: #pragma omp ordered depend(sink : i - 5)
|
||||
#if _OPENMP >= 202111
|
||||
// OMP52: #pragma omp ordered doacross(source:)
|
||||
// OMP52-NEXT: #pragma omp ordered doacross(sink: i - 5)
|
||||
#else
|
||||
// OMP51: #pragma omp ordered depend(source)
|
||||
// OMP51-NEXT: #pragma omp ordered depend(sink : i - 5)
|
||||
#endif
|
||||
// CHECK-NEXT: a = 2;
|
||||
// CHECK-NEXT: }
|
||||
return tmain<int, 3>(argc);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -o - %s -Wuninitialized
|
||||
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++98 -o - %s -Wuninitialized
|
||||
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 -std=c++11 -o - %s -Wuninitialized
|
||||
// RUN: %clang_cc1 -verify=expected,omp52 -fopenmp -fopenmp-version=52 -ferror-limit 100 -o - %s -Wuninitialized
|
||||
|
||||
// RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 -o - %s -Wuninitialized
|
||||
// RUN: %clang_cc1 -verify -fopenmp-simd -ferror-limit 100 -std=c++98 -o - %s -Wuninitialized
|
||||
@ -135,12 +136,48 @@ T foo() {
|
||||
}
|
||||
#pragma omp parallel for ordered
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
#if _OPENMP >= 202111
|
||||
#pragma omp ordered doacross(source:) // omp52-error {{'ordered' directive with 'doacross' clause cannot be closely nested inside ordered region without specified parameter}}
|
||||
#pragma omp ordered doacross(sink : i) // omp52-error {{'ordered' directive with 'doacross' clause cannot be closely nested inside ordered region without specified parameter}}
|
||||
#else
|
||||
#pragma omp ordered depend(source) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}}
|
||||
#pragma omp ordered depend(sink : i) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}}
|
||||
#endif
|
||||
}
|
||||
#pragma omp parallel for ordered(2) // expected-note 3 {{'ordered' clause with specified parameter}}
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
for (int j = 0; j < 10; ++j) {
|
||||
#if _OPENMP >= 202111
|
||||
#pragma omp ordered doacross // omp52-error {{expected '(' after 'doacross'}} omp52-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
|
||||
#pragma omp ordered doacross( // omp52-error {{expected ')'}} omp52-error {{expected 'source' or 'sink' in OpenMP clause 'doacross'}} omp52-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} omp52-warning {{missing ':' or ')' after dependence-type - ignoring}} omp52-note {{to match this '('}}
|
||||
#pragma omp ordered doacross(source // omp52-warning {{missing ':' or ')' after dependence-type - ignoring}} omp52-error {{expected ')'}} omp52-note {{to match this '('}}
|
||||
#pragma omp ordered doacross(sink // omp52-error {{expected expression}} omp52-warning {{missing ':' or ')' after dependence-type - ignoring}} omp52-error {{expected ')'}} omp52-note {{to match this '('}} omp52-error {{expected 'i' loop iteration variable}}
|
||||
#pragma omp ordered doacross(sink : // omp52-error {{expected ')'}} omp52-note {{to match this '('}} omp52-error {{expected expression}} omp52-error {{expected 'i' loop iteration variable}}
|
||||
#pragma omp ordered doacross(sink : i // omp52-error {{expected ')'}} omp52-note {{to match this '('}} omp52-error {{expected 'j' loop iteration variable}}
|
||||
#pragma omp ordered doacross(sink : i) // omp52-error {{expected 'j' loop iteration variable}}
|
||||
#pragma omp ordered doacross(source:)
|
||||
if (i == j)
|
||||
#pragma omp ordered doacross(source:) // omp52-error {{'#pragma omp ordered' with 'doacross' clause cannot be an immediate substatement}}
|
||||
;
|
||||
if (i == j)
|
||||
#pragma omp ordered doacross(sink : i, j) // omp52-error {{'#pragma omp ordered' with 'doacross' clause cannot be an immediate substatement}}
|
||||
;
|
||||
#pragma omp ordered doacross(source:) threads // omp52-error {{'doacross' clauses cannot be mixed with 'threads' clause}}
|
||||
#pragma omp ordered simd doacross(source:) // omp52-error {{'doacross' clauses cannot be mixed with 'simd' clause}}
|
||||
#pragma omp ordered doacross(source:) doacross(source:) // omp52-error {{directive '#pragma omp ordered' cannot contain more than one 'doacross' clause with 'source' dependence}}
|
||||
#pragma omp ordered doacross(in : i) // omp52-error {{expected 'source' or 'sink' in OpenMP clause 'doacross'}} omp52-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
|
||||
#pragma omp ordered doacross(sink : i, j)
|
||||
#pragma omp ordered doacross(sink : j, i) // omp52-error {{expected 'i' loop iteration variable}} omp52-error {{expected 'j' loop iteration variable}}
|
||||
#pragma omp ordered doacross(sink : i, j, k) // omp52-error {{unexpected expression: number of expressions is larger than the number of associated loops}}
|
||||
#pragma omp ordered doacross(sink : i+foo(), j/4) // omp52-error {{integral constant expression}} omp52-error {{expected '+' or '-' operation}}
|
||||
#if __cplusplus >= 201103L
|
||||
// omp52-note@-2 {{non-constexpr function 'foo' cannot be used in a constant expression}}
|
||||
#endif
|
||||
#pragma omp ordered doacross(sink : i*0, j-4)// omp52-error {{expected '+' or '-' operation}}
|
||||
#pragma omp ordered doacross(sink : i-0, j+sizeof(T)) doacross(sink : i-0, j+sizeof(T))
|
||||
#pragma omp ordered doacross(sink : i-0, j+sizeof(T)) doacross(source:) // omp52-error {{'doacross(source)' clause cannot be mixed with 'doacross(sink:vec)' clauses}}
|
||||
#pragma omp ordered doacross(source:) doacross(sink : i-0, j+sizeof(T)) // omp52-error {{'doacross(sink:vec)' clauses cannot be mixed with 'doacross(source)' clause}}
|
||||
#else
|
||||
#pragma omp ordered depend // expected-error {{expected '(' after 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
|
||||
#pragma omp ordered depend( // expected-error {{expected ')'}} expected-error {{expected 'source' or 'sink' in OpenMP clause 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} expected-warning {{missing ':' or ')' after dependency type - ignoring}} expected-note {{to match this '('}}
|
||||
#pragma omp ordered depend(source // expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||
@ -170,10 +207,14 @@ T foo() {
|
||||
#pragma omp ordered depend(sink : i-0, j+sizeof(T)) depend(sink : i-0, j+sizeof(T))
|
||||
#pragma omp ordered depend(sink : i-0, j+sizeof(T)) depend(source) // expected-error {{'depend(source)' clause cannot be mixed with 'depend(sink:vec)' clauses}}
|
||||
#pragma omp ordered depend(source) depend(sink : i-0, j+sizeof(T)) // expected-error {{'depend(sink:vec)' clauses cannot be mixed with 'depend(source)' clause}}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if _OPENMP >= 202111
|
||||
#else
|
||||
#pragma omp ordered depend(source) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}}
|
||||
#pragma omp ordered depend(sink:k) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}}
|
||||
#endif
|
||||
return T();
|
||||
}
|
||||
|
||||
@ -272,12 +313,46 @@ int k;
|
||||
}
|
||||
#pragma omp parallel for ordered
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
#if _OPENMP >= 202111
|
||||
#else
|
||||
#pragma omp ordered depend(source) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}}
|
||||
#pragma omp ordered depend(sink : i) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}}
|
||||
#endif
|
||||
}
|
||||
#pragma omp parallel for ordered(2) // expected-note 3 {{'ordered' clause with specified parameter}}
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
for (int j = 0; j < 10; ++j) {
|
||||
#if _OPENMP >= 202111
|
||||
#pragma omp ordered doacross // omp52-error {{expected '(' after 'doacross'}} omp52-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
|
||||
#pragma omp ordered doacross( // omp52-error {{expected ')'}} omp52-error {{expected 'source' or 'sink' in OpenMP clause 'doacross'}} omp52-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} omp52-warning {{missing ':' or ')' after dependence-type - ignoring}} omp52-note {{to match this '('}}
|
||||
#pragma omp ordered doacross(source // omp52-warning {{missing ':' or ')' after dependence-type - ignoring}} omp52-error {{expected ')'}} omp52-note {{to match this '('}}
|
||||
#pragma omp ordered doacross(sink // omp52-error {{expected expression}} omp52-warning {{missing ':' or ')' after dependence-type - ignoring}} omp52-error {{expected ')'}} omp52-note {{to match this '('}} omp52-error {{expected 'i' loop iteration variable}}
|
||||
#pragma omp ordered doacross(sink : // omp52-error {{expected ')'}} omp52-note {{to match this '('}} omp52-error {{expected expression}} omp52-error {{expected 'i' loop iteration variable}}
|
||||
#pragma omp ordered doacross(sink : i // omp52-error {{expected ')'}} omp52-note {{to match this '('}} omp52-error {{expected 'j' loop iteration variable}}
|
||||
#pragma omp ordered doacross(sink : i) // omp52-error {{expected 'j' loop iteration variable}}
|
||||
#pragma omp ordered doacross(source:)
|
||||
if (i == j)
|
||||
#pragma omp ordered doacross(source:) // omp52-error {{'#pragma omp ordered' with 'doacross' clause cannot be an immediate substatement}}
|
||||
;
|
||||
if (i == j)
|
||||
#pragma omp ordered doacross(sink : i, j) // omp52-error {{'#pragma omp ordered' with 'doacross' clause cannot be an immediate substatement}}
|
||||
;
|
||||
#pragma omp ordered doacross(source:) threads // omp52-error {{'doacross' clauses cannot be mixed with 'threads' clause}}
|
||||
#pragma omp ordered simd doacross(source:) // omp52-error {{'doacross' clauses cannot be mixed with 'simd' clause}}
|
||||
#pragma omp ordered doacross(source:) doacross(source:) // omp52-error {{directive '#pragma omp ordered' cannot contain more than one 'doacross' clause with 'source' dependence}}
|
||||
#pragma omp ordered doacross(in : i) // omp52-error {{expected 'source' or 'sink' in OpenMP clause 'doacross'}} omp52-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
|
||||
#pragma omp ordered doacross(sink : i, j) allocate(i) // omp52-error {{unexpected OpenMP clause 'allocate' in directive '#pragma omp ordered'}}
|
||||
#pragma omp ordered doacross(sink : j, i) // omp52-error {{expected 'i' loop iteration variable}} omp52-error {{expected 'j' loop iteration variable}}
|
||||
#pragma omp ordered doacross(sink : i, j, k) // omp52-error {{unexpected expression: number of expressions is larger than the number of associated loops}}
|
||||
#pragma omp ordered doacross(sink : i+foo(), j/4) // omp52-error {{integral constant expression}} omp52-error {{expected '+' or '-' operation}}
|
||||
#if __cplusplus >= 201103L
|
||||
// omp52-note@-2 {{non-constexpr function 'foo' cannot be used in a constant expression}}
|
||||
#endif
|
||||
#pragma omp ordered doacross(sink : i*0, j-4)// omp52-error {{expected '+' or '-' operation}}
|
||||
#pragma omp ordered doacross(sink : i-0, j+sizeof(int)) doacross(sink : i-0, j+sizeof(int))
|
||||
#pragma omp ordered doacross(sink : i-0, j+sizeof(int)) doacross(source:) // omp52-error {{'doacross(source)' clause cannot be mixed with 'doacross(sink:vec)' clauses}}
|
||||
#pragma omp ordered doacross(source:) doacross(sink : i-0, j+sizeof(int)) // omp52-error {{'doacross(sink:vec)' clauses cannot be mixed with 'doacross(source)' clause}}
|
||||
#else
|
||||
#pragma omp ordered depend // expected-error {{expected '(' after 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
|
||||
#pragma omp ordered depend( // expected-error {{expected ')'}} expected-error {{expected 'source' or 'sink' in OpenMP clause 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} expected-warning {{missing ':' or ')' after dependency type - ignoring}} expected-note {{to match this '('}}
|
||||
#pragma omp ordered depend(source // expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||
@ -307,14 +382,21 @@ int k;
|
||||
#pragma omp ordered depend(sink : i-0, j+sizeof(int)) depend(sink : i-0, j+sizeof(int))
|
||||
#pragma omp ordered depend(sink : i-0, j+sizeof(int)) depend(source) // expected-error {{'depend(source)' clause cannot be mixed with 'depend(sink:vec)' clauses}}
|
||||
#pragma omp ordered depend(source) depend(sink : i-0, j+sizeof(int)) // expected-error {{'depend(sink:vec)' clauses cannot be mixed with 'depend(source)' clause}}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp for ordered(2) // expected-note {{as specified in 'ordered' clause}}
|
||||
for (int i = 0; i < 10; ++i) { // expected-error {{expected 2 for loops after '#pragma omp for', but found only 1}}
|
||||
#if _OPENMP >= 202111
|
||||
#pragma omp ordered doacross(sink : i)
|
||||
int j;
|
||||
#pragma omp ordered doacross(sink : i, j) // omp52-error {{expected loop iteration variable}}
|
||||
#else
|
||||
#pragma omp ordered depend(sink : i)
|
||||
int j;
|
||||
#pragma omp ordered depend(sink : i, j) // expected-error {{expected loop iteration variable}}
|
||||
#endif
|
||||
foo();
|
||||
}
|
||||
|
||||
|
||||
@ -2717,6 +2717,9 @@ void OMPClauseEnqueue::VisitOMPXDynCGroupMemClause(
|
||||
VisitOMPClauseWithPreInit(C);
|
||||
Visitor->AddStmt(C->getSize());
|
||||
}
|
||||
void OMPClauseEnqueue::VisitOMPDoacrossClause(const OMPDoacrossClause *C) {
|
||||
VisitOMPClauseList(C);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
@ -1937,6 +1937,7 @@ CHECK_SIMPLE_CLAUSE(Bind, OMPC_bind)
|
||||
CHECK_SIMPLE_CLAUSE(Align, OMPC_align)
|
||||
CHECK_SIMPLE_CLAUSE(Compare, OMPC_compare)
|
||||
CHECK_SIMPLE_CLAUSE(CancellationConstructType, OMPC_cancellation_construct_type)
|
||||
CHECK_SIMPLE_CLAUSE(Doacross, OMPC_doacross)
|
||||
|
||||
CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize)
|
||||
CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks)
|
||||
|
||||
@ -444,6 +444,10 @@ def OMPC_OMPX_DynCGroupMem : Clause<"ompx_dyn_cgroup_mem"> {
|
||||
let flangClass = "ScalarIntExpr";
|
||||
}
|
||||
|
||||
def OMPC_Doacross : Clause<"doacross"> {
|
||||
let clangClass = "OMPDoacrossClause";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Definition of OpenMP directives
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -604,7 +608,8 @@ def OMP_Flush : Directive<"flush"> {
|
||||
}
|
||||
def OMP_Ordered : Directive<"ordered"> {
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Depend>
|
||||
VersionedClause<OMPC_Depend>,
|
||||
VersionedClause<OMPC_Doacross, 52>
|
||||
];
|
||||
let allowedOnceClauses = [
|
||||
VersionedClause<OMPC_Threads>,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user