forked from OSchip/llvm-project
[OPENMP] Initial support of 'reduction' clause
llvm-svn: 211007
This commit is contained in:
parent
43ab82c562
commit
c5e025831b
|
@ -2391,6 +2391,15 @@ bool RecursiveASTVisitor<Derived>::VisitOMPCopyinClause(OMPCopyinClause *C) {
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool DataRecursiveASTVisitor<Derived>::VisitOMPReductionClause(
|
||||
OMPReductionClause *C) {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
|
||||
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
|
||||
|
|
|
@ -431,7 +431,8 @@ public:
|
|||
StmtRange children() { return StmtRange(); }
|
||||
};
|
||||
|
||||
/// \brief This represents 'proc_bind' clause in the '#pragma omp ...' directive.
|
||||
/// \brief This represents 'proc_bind' clause in the '#pragma omp ...'
|
||||
/// directive.
|
||||
///
|
||||
/// \code
|
||||
/// #pragma omp parallel proc_bind(master)
|
||||
|
@ -471,8 +472,8 @@ public:
|
|||
/// \param EndLoc Ending location of the clause.
|
||||
///
|
||||
OMPProcBindClause(OpenMPProcBindClauseKind A, SourceLocation ALoc,
|
||||
SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc)
|
||||
SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc)
|
||||
: OMPClause(OMPC_proc_bind, StartLoc, EndLoc), LParenLoc(LParenLoc),
|
||||
Kind(A), KindKwLoc(ALoc) {}
|
||||
|
||||
|
@ -739,6 +740,99 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// \brief This represents clause 'reduction' in the '#pragma omp ...'
|
||||
/// directives.
|
||||
///
|
||||
/// \code
|
||||
/// #pragma omp parallel reduction(+:a,b)
|
||||
/// \endcode
|
||||
/// In this example directive '#pragma omp parallel' has clause 'reduction'
|
||||
/// with operator '+' and the variables 'a' and 'b'.
|
||||
///
|
||||
class OMPReductionClause : public OMPVarListClause<OMPReductionClause> {
|
||||
friend class OMPClauseReader;
|
||||
/// \brief Location of ':'.
|
||||
SourceLocation ColonLoc;
|
||||
/// \brief Nested name specifier for C++.
|
||||
NestedNameSpecifierLoc QualifierLoc;
|
||||
/// \brief Name of custom operator.
|
||||
DeclarationNameInfo NameInfo;
|
||||
|
||||
/// \brief Build clause with number of variables \a N.
|
||||
///
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
/// \param ColonLoc Location of ':'.
|
||||
/// \param N Number of the variables in the clause.
|
||||
/// \param QualifierLoc The nested-name qualifier with location information
|
||||
/// \param NameInfo The full name info for reduction identifier.
|
||||
///
|
||||
OMPReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation ColonLoc, SourceLocation EndLoc, unsigned N,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
const DeclarationNameInfo &NameInfo)
|
||||
: OMPVarListClause<OMPReductionClause>(OMPC_reduction, StartLoc,
|
||||
LParenLoc, EndLoc, N),
|
||||
ColonLoc(ColonLoc), QualifierLoc(QualifierLoc), NameInfo(NameInfo) {}
|
||||
|
||||
/// \brief Build an empty clause.
|
||||
///
|
||||
/// \param N Number of variables.
|
||||
///
|
||||
explicit OMPReductionClause(unsigned N)
|
||||
: OMPVarListClause<OMPReductionClause>(OMPC_reduction, SourceLocation(),
|
||||
SourceLocation(), SourceLocation(),
|
||||
N),
|
||||
ColonLoc(), QualifierLoc(), NameInfo() {}
|
||||
|
||||
/// \brief Sets location of ':' symbol in clause.
|
||||
void setColonLoc(SourceLocation CL) { ColonLoc = CL; }
|
||||
/// \brief Sets the name info for specified reduction identifier.
|
||||
void setNameInfo(DeclarationNameInfo DNI) { NameInfo = DNI; }
|
||||
/// \brief Sets the nested name specifier.
|
||||
void setQualifierLoc(NestedNameSpecifierLoc NSL) { QualifierLoc = NSL; }
|
||||
|
||||
public:
|
||||
/// \brief Creates clause with a list of variables \a VL.
|
||||
///
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param ColonLoc Location of ':'.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
/// \param N Number of the variables in the clause.
|
||||
/// \param QualifierLoc The nested-name qualifier with location information
|
||||
/// \param NameInfo The full name info for reduction identifier.
|
||||
///
|
||||
static OMPReductionClause *
|
||||
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
const DeclarationNameInfo &NameInfo);
|
||||
/// \brief Creates an empty clause with the place for \a N variables.
|
||||
///
|
||||
/// \param C AST context.
|
||||
/// \param N The number of variables.
|
||||
///
|
||||
static OMPReductionClause *CreateEmpty(const ASTContext &C, unsigned N);
|
||||
|
||||
/// \brief Gets location of ':' symbol in clause.
|
||||
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||
/// \brief Gets the name info for specified reduction identifier.
|
||||
const DeclarationNameInfo &getNameInfo() const { return NameInfo; }
|
||||
/// \brief Gets the nested name specifier.
|
||||
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
|
||||
|
||||
StmtRange children() {
|
||||
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
|
||||
reinterpret_cast<Stmt **>(varlist_end()));
|
||||
}
|
||||
|
||||
static bool classof(const OMPClause *T) {
|
||||
return T->getClauseKind() == OMPC_reduction;
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief This represents clause 'linear' in the '#pragma omp ...'
|
||||
/// directives.
|
||||
///
|
||||
|
|
|
@ -2393,6 +2393,15 @@ bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) {
|
|||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPReductionClause(
|
||||
OMPReductionClause *C) {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc()));
|
||||
TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo()));
|
||||
VisitOMPClauseList(C);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPLinearClause(OMPLinearClause *C) {
|
||||
VisitOMPClauseList(C);
|
||||
TraverseStmt(C->getStep());
|
||||
|
|
|
@ -6965,6 +6965,8 @@ def err_omp_firstprivate_incomplete_type : Error<
|
|||
"a firstprivate variable with incomplete type %0">;
|
||||
def err_omp_lastprivate_incomplete_type : Error<
|
||||
"a lastprivate variable with incomplete type %0">;
|
||||
def err_omp_reduction_incomplete_type : Error<
|
||||
"a reduction variable with incomplete type %0">;
|
||||
def err_omp_unexpected_clause_value : Error<
|
||||
"expected %0 in OpenMP clause '%1'">;
|
||||
def err_omp_expected_var_name : Error<
|
||||
|
@ -7044,6 +7046,24 @@ def err_omp_loop_cannot_use_stmt : Error<
|
|||
"'%0' statement cannot be used in OpenMP for loop">;
|
||||
def err_omp_simd_region_cannot_use_stmt : Error<
|
||||
"'%0' statement cannot be used in OpenMP simd region">;
|
||||
def err_omp_unknown_reduction_identifier : Error<
|
||||
"incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'">;
|
||||
def err_omp_reduction_type_array : Error<
|
||||
"a reduction variable with array type %0">;
|
||||
def err_omp_reduction_ref_type_arg : Error<
|
||||
"argument of OpenMP clause 'reduction' must reference the same object in all threads">;
|
||||
def err_omp_clause_not_arithmetic_type_arg : Error<
|
||||
"arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of %select{scalar|arithmetic}0 type">;
|
||||
def err_omp_clause_floating_type_arg : Error<
|
||||
"arguments of OpenMP clause 'reduction' with bitwise operators cannot be of floating type">;
|
||||
def err_omp_once_referenced : Error<
|
||||
"variable can appear only once in OpenMP '%0' clause">;
|
||||
def note_omp_referenced : Note<
|
||||
"previously referenced here">;
|
||||
def err_omp_reduction_in_task : Error<
|
||||
"reduction variables may not be accessed in an explicit task">;
|
||||
def err_omp_reduction_id_not_compatible : Error<
|
||||
"variable of type %0 is not valid for specified reduction operation">;
|
||||
} // end of OpenMP category
|
||||
|
||||
let CategoryName = "Related Result Type Issue" in {
|
||||
|
|
|
@ -47,6 +47,7 @@ OPENMP_CLAUSE(private, OMPPrivateClause)
|
|||
OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause)
|
||||
OPENMP_CLAUSE(lastprivate, OMPLastprivateClause)
|
||||
OPENMP_CLAUSE(shared, OMPSharedClause)
|
||||
OPENMP_CLAUSE(reduction, OMPReductionClause)
|
||||
OPENMP_CLAUSE(linear, OMPLinearClause)
|
||||
OPENMP_CLAUSE(aligned, OMPAlignedClause)
|
||||
OPENMP_CLAUSE(copyin, OMPCopyinClause)
|
||||
|
@ -60,6 +61,7 @@ OPENMP_PARALLEL_CLAUSE(proc_bind)
|
|||
OPENMP_PARALLEL_CLAUSE(private)
|
||||
OPENMP_PARALLEL_CLAUSE(firstprivate)
|
||||
OPENMP_PARALLEL_CLAUSE(shared)
|
||||
OPENMP_PARALLEL_CLAUSE(reduction)
|
||||
OPENMP_PARALLEL_CLAUSE(copyin)
|
||||
|
||||
// FIXME: more clauses allowed for directive 'omp simd'.
|
||||
|
|
|
@ -7355,13 +7355,13 @@ public:
|
|||
SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc);
|
||||
|
||||
OMPClause *ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
|
||||
ArrayRef<Expr *> Vars,
|
||||
Expr *TailExpr,
|
||||
SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation ColonLoc,
|
||||
SourceLocation EndLoc);
|
||||
OMPClause *
|
||||
ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef<Expr *> Vars,
|
||||
Expr *TailExpr, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc, SourceLocation ColonLoc,
|
||||
SourceLocation EndLoc,
|
||||
CXXScopeSpec &ReductionIdScopeSpec,
|
||||
const DeclarationNameInfo &ReductionId);
|
||||
/// \brief Called on well-formed 'private' clause.
|
||||
OMPClause *ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
|
||||
SourceLocation StartLoc,
|
||||
|
@ -7382,6 +7382,13 @@ public:
|
|||
SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc);
|
||||
/// \brief Called on well-formed 'reduction' clause.
|
||||
OMPClause *
|
||||
ActOnOpenMPReductionClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc, SourceLocation ColonLoc,
|
||||
SourceLocation EndLoc,
|
||||
CXXScopeSpec &ReductionIdScopeSpec,
|
||||
const DeclarationNameInfo &ReductionId);
|
||||
/// \brief Called on well-formed 'linear' clause.
|
||||
OMPClause *ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList,
|
||||
Expr *Step,
|
||||
|
|
|
@ -1286,6 +1286,27 @@ void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> Clauses) {
|
|||
std::copy(Clauses.begin(), Clauses.end(), getClauses().begin());
|
||||
}
|
||||
|
||||
OMPReductionClause *OMPReductionClause::Create(
|
||||
const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL,
|
||||
NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo) {
|
||||
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
|
||||
llvm::alignOf<Expr *>()) +
|
||||
sizeof(Expr *) * VL.size());
|
||||
OMPReductionClause *Clause = new (Mem) OMPReductionClause(
|
||||
StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo);
|
||||
Clause->setVarRefs(VL);
|
||||
return Clause;
|
||||
}
|
||||
|
||||
OMPReductionClause *OMPReductionClause::CreateEmpty(const ASTContext &C,
|
||||
unsigned N) {
|
||||
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause),
|
||||
llvm::alignOf<Expr *>()) +
|
||||
sizeof(Expr *) * N);
|
||||
return new (Mem) OMPReductionClause(N);
|
||||
}
|
||||
|
||||
OMPParallelDirective *OMPParallelDirective::Create(
|
||||
const ASTContext &C,
|
||||
SourceLocation StartLoc,
|
||||
|
|
|
@ -676,6 +676,28 @@ void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) {
|
|||
}
|
||||
}
|
||||
|
||||
void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause *Node) {
|
||||
if (!Node->varlist_empty()) {
|
||||
OS << "reduction(";
|
||||
NestedNameSpecifier *QualifierLoc =
|
||||
Node->getQualifierLoc().getNestedNameSpecifier();
|
||||
OverloadedOperatorKind OOK =
|
||||
Node->getNameInfo().getName().getCXXOverloadedOperator();
|
||||
if (QualifierLoc == nullptr && OOK != OO_None) {
|
||||
// Print reduction identifier in C format
|
||||
OS << getOperatorSpelling(OOK);
|
||||
} else {
|
||||
// Use C++ format
|
||||
if (QualifierLoc != nullptr)
|
||||
QualifierLoc->print(OS, Policy);
|
||||
OS << Node->getNameInfo();
|
||||
}
|
||||
OS << ":";
|
||||
VisitOMPClauseList(Node, ' ');
|
||||
OS << ")";
|
||||
}
|
||||
}
|
||||
|
||||
void OMPClausePrinter::VisitOMPLinearClause(OMPLinearClause *Node) {
|
||||
if (!Node->varlist_empty()) {
|
||||
OS << "linear";
|
||||
|
|
|
@ -308,6 +308,13 @@ OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) {
|
|||
void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) {
|
||||
VisitOMPClauseList(C);
|
||||
}
|
||||
void OMPClauseProfiler::VisitOMPReductionClause(
|
||||
const OMPReductionClause *C) {
|
||||
Profiler->VisitNestedNameSpecifier(
|
||||
C->getQualifierLoc().getNestedNameSpecifier());
|
||||
Profiler->VisitName(C->getNameInfo().getName());
|
||||
VisitOMPClauseList(C);
|
||||
}
|
||||
void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) {
|
||||
VisitOMPClauseList(C);
|
||||
Profiler->VisitStmt(C->getStep());
|
||||
|
|
|
@ -88,6 +88,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
|
|||
case OMPC_firstprivate:
|
||||
case OMPC_lastprivate:
|
||||
case OMPC_shared:
|
||||
case OMPC_reduction:
|
||||
case OMPC_linear:
|
||||
case OMPC_aligned:
|
||||
case OMPC_copyin:
|
||||
|
@ -127,6 +128,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
|
|||
case OMPC_firstprivate:
|
||||
case OMPC_lastprivate:
|
||||
case OMPC_shared:
|
||||
case OMPC_reduction:
|
||||
case OMPC_linear:
|
||||
case OMPC_aligned:
|
||||
case OMPC_copyin:
|
||||
|
|
|
@ -258,7 +258,8 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
|
|||
/// clause:
|
||||
/// if-clause | num_threads-clause | safelen-clause | default-clause |
|
||||
/// private-clause | firstprivate-clause | shared-clause | linear-clause |
|
||||
/// aligned-clause | collapse-clause | lastprivate-clause
|
||||
/// aligned-clause | collapse-clause | lastprivate-clause |
|
||||
/// reduction-clause
|
||||
///
|
||||
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
|
||||
OpenMPClauseKind CKind, bool FirstClause) {
|
||||
|
@ -307,6 +308,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
|
|||
case OMPC_firstprivate:
|
||||
case OMPC_lastprivate:
|
||||
case OMPC_shared:
|
||||
case OMPC_reduction:
|
||||
case OMPC_linear:
|
||||
case OMPC_aligned:
|
||||
case OMPC_copyin:
|
||||
|
@ -394,6 +396,52 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
|
|||
Tok.getLocation());
|
||||
}
|
||||
|
||||
static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
|
||||
UnqualifiedId &ReductionId) {
|
||||
SourceLocation TemplateKWLoc;
|
||||
if (ReductionIdScopeSpec.isEmpty()) {
|
||||
auto OOK = OO_None;
|
||||
switch (P.getCurToken().getKind()) {
|
||||
case tok::plus:
|
||||
OOK = OO_Plus;
|
||||
break;
|
||||
case tok::minus:
|
||||
OOK = OO_Minus;
|
||||
break;
|
||||
case tok::star:
|
||||
OOK = OO_Star;
|
||||
break;
|
||||
case tok::amp:
|
||||
OOK = OO_Amp;
|
||||
break;
|
||||
case tok::pipe:
|
||||
OOK = OO_Pipe;
|
||||
break;
|
||||
case tok::caret:
|
||||
OOK = OO_Caret;
|
||||
break;
|
||||
case tok::ampamp:
|
||||
OOK = OO_AmpAmp;
|
||||
break;
|
||||
case tok::pipepipe:
|
||||
OOK = OO_PipePipe;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (OOK != OO_None) {
|
||||
SourceLocation OpLoc = P.ConsumeToken();
|
||||
SourceLocation SymbolLocations[] = { OpLoc, OpLoc, SourceLocation() };
|
||||
ReductionId.setOperatorFunctionId(OpLoc, OOK, SymbolLocations);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false,
|
||||
/*AllowDestructorName*/ false,
|
||||
/*AllowConstructorName*/ false, ParsedType(),
|
||||
TemplateKWLoc, ReductionId);
|
||||
}
|
||||
|
||||
/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
|
||||
/// 'shared', 'copyin', or 'reduction'.
|
||||
///
|
||||
|
@ -409,19 +457,44 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
|
|||
/// 'linear' '(' list [ ':' linear-step ] ')'
|
||||
/// aligned-clause:
|
||||
/// 'aligned' '(' list [ ':' alignment ] ')'
|
||||
/// reduction-clause:
|
||||
/// 'reduction' '(' reduction-identifier ':' list ')'
|
||||
///
|
||||
OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
|
||||
SourceLocation Loc = Tok.getLocation();
|
||||
SourceLocation LOpen = ConsumeToken();
|
||||
SourceLocation ColonLoc = SourceLocation();
|
||||
// Optional scope specifier and unqualified id for reduction identifier.
|
||||
CXXScopeSpec ReductionIdScopeSpec;
|
||||
UnqualifiedId ReductionId;
|
||||
bool InvalidReductionId = false;
|
||||
// Parse '('.
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
|
||||
if (T.expectAndConsume(diag::err_expected_lparen_after,
|
||||
getOpenMPClauseName(Kind)))
|
||||
return nullptr;
|
||||
|
||||
// Handle reduction-identifier for reduction clause.
|
||||
if (Kind == OMPC_reduction) {
|
||||
ColonProtectionRAIIObject ColonRAII(*this);
|
||||
if (getLangOpts().CPlusPlus) {
|
||||
ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec, ParsedType(), false);
|
||||
}
|
||||
InvalidReductionId =
|
||||
ParseReductionId(*this, ReductionIdScopeSpec, ReductionId);
|
||||
if (InvalidReductionId) {
|
||||
SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
|
||||
StopBeforeMatch);
|
||||
}
|
||||
if (Tok.is(tok::colon)) {
|
||||
ColonLoc = ConsumeToken();
|
||||
} else {
|
||||
Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier";
|
||||
}
|
||||
}
|
||||
|
||||
SmallVector<Expr *, 5> Vars;
|
||||
bool IsComma = true;
|
||||
bool IsComma = !InvalidReductionId;
|
||||
const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);
|
||||
while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
|
||||
Tok.isNot(tok::annot_pragma_openmp_end))) {
|
||||
|
@ -460,10 +533,13 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
|
|||
|
||||
// Parse ')'.
|
||||
T.consumeClose();
|
||||
if (Vars.empty() || (MustHaveTail && !TailExpr))
|
||||
if (Vars.empty() || (MustHaveTail && !TailExpr) || InvalidReductionId)
|
||||
return nullptr;
|
||||
|
||||
return Actions.ActOnOpenMPVarListClause(Kind, Vars, TailExpr, Loc, LOpen,
|
||||
ColonLoc, Tok.getLocation());
|
||||
return Actions.ActOnOpenMPVarListClause(
|
||||
Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(),
|
||||
ReductionIdScopeSpec,
|
||||
ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId)
|
||||
: DeclarationNameInfo());
|
||||
}
|
||||
|
||||
|
|
|
@ -119,6 +119,10 @@ public:
|
|||
/// attribute in \a DKind directive.
|
||||
DSAVarData hasDSA(VarDecl *D, OpenMPClauseKind CKind,
|
||||
OpenMPDirectiveKind DKind = OMPD_unknown);
|
||||
/// \brief Checks if the specified variables has \a CKind data-sharing
|
||||
/// attribute in an innermost \a DKind directive.
|
||||
DSAVarData hasInnermostDSA(VarDecl *D, OpenMPClauseKind CKind,
|
||||
OpenMPDirectiveKind DKind);
|
||||
|
||||
/// \brief Returns currently analyzed directive.
|
||||
OpenMPDirectiveKind getCurrentDirective() const {
|
||||
|
@ -154,7 +158,6 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
|
|||
// File-scope or namespace-scope variables referenced in called routines
|
||||
// in the region are shared unless they appear in a threadprivate
|
||||
// directive.
|
||||
// TODO
|
||||
if (!D->isFunctionOrMethodVarDecl())
|
||||
DVar.CKind = OMPC_shared;
|
||||
|
||||
|
@ -214,7 +217,6 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
|
|||
// In a task construct, if no default clause is present, a variable that in
|
||||
// the enclosing context is determined to be shared by all implicit tasks
|
||||
// bound to the current team is shared.
|
||||
// TODO
|
||||
if (DVar.DKind == OMPD_task) {
|
||||
DSAVarData DVarTemp;
|
||||
for (StackTy::reverse_iterator I = std::next(Iter),
|
||||
|
@ -399,6 +401,21 @@ DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, OpenMPClauseKind CKind,
|
|||
return DSAVarData();
|
||||
}
|
||||
|
||||
DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(VarDecl *D,
|
||||
OpenMPClauseKind CKind,
|
||||
OpenMPDirectiveKind DKind) {
|
||||
assert(DKind != OMPD_unknown && "Directive must be specified explicitly");
|
||||
for (auto I = Stack.rbegin(), EE = std::prev(Stack.rend()); I != EE; ++I) {
|
||||
if (DKind != I->Directive)
|
||||
continue;
|
||||
DSAVarData DVar = getDSA(I, D);
|
||||
if (DVar.CKind == CKind)
|
||||
return DVar;
|
||||
return DSAVarData();
|
||||
}
|
||||
return DSAVarData();
|
||||
}
|
||||
|
||||
void Sema::InitDataSharingAttributesStack() {
|
||||
VarDataSharingAttributesStack = new DSAStackTy(*this);
|
||||
}
|
||||
|
@ -702,7 +719,16 @@ public:
|
|||
// A list item that appears in a reduction clause of the innermost
|
||||
// enclosing worksharing or parallel construct may not be accessed in an
|
||||
// explicit task.
|
||||
// TODO:
|
||||
DVar = Stack->hasInnermostDSA(VD, OMPC_reduction, OMPD_parallel);
|
||||
if (DKind == OMPD_task && DVar.CKind == OMPC_reduction) {
|
||||
ErrorFound = true;
|
||||
Actions.Diag(ELoc, diag::err_omp_reduction_in_task);
|
||||
if (DVar.RefExpr) {
|
||||
Actions.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
|
||||
<< getOpenMPClauseName(OMPC_reduction);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Define implicit data-sharing attributes for task.
|
||||
DVar = Stack->getImplicitDSA(VD);
|
||||
|
@ -1357,6 +1383,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
|
|||
case OMPC_firstprivate:
|
||||
case OMPC_lastprivate:
|
||||
case OMPC_shared:
|
||||
case OMPC_reduction:
|
||||
case OMPC_linear:
|
||||
case OMPC_aligned:
|
||||
case OMPC_copyin:
|
||||
|
@ -1532,6 +1559,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
|
|||
case OMPC_firstprivate:
|
||||
case OMPC_lastprivate:
|
||||
case OMPC_shared:
|
||||
case OMPC_reduction:
|
||||
case OMPC_linear:
|
||||
case OMPC_aligned:
|
||||
case OMPC_copyin:
|
||||
|
@ -1617,11 +1645,11 @@ OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind,
|
|||
OMPProcBindClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
|
||||
}
|
||||
|
||||
OMPClause *
|
||||
Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef<Expr *> VarList,
|
||||
Expr *TailExpr, SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation ColonLoc, SourceLocation EndLoc) {
|
||||
OMPClause *Sema::ActOnOpenMPVarListClause(
|
||||
OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
|
||||
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
|
||||
SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec,
|
||||
const DeclarationNameInfo &ReductionId) {
|
||||
OMPClause *Res = nullptr;
|
||||
switch (Kind) {
|
||||
case OMPC_private:
|
||||
|
@ -1636,6 +1664,11 @@ Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef<Expr *> VarList,
|
|||
case OMPC_shared:
|
||||
Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
|
||||
break;
|
||||
case OMPC_reduction:
|
||||
Res =
|
||||
ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
|
||||
EndLoc, ReductionIdScopeSpec, ReductionId);
|
||||
break;
|
||||
case OMPC_linear:
|
||||
Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
|
||||
ColonLoc, EndLoc);
|
||||
|
@ -2194,6 +2227,323 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
|
|||
return OMPSharedClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
|
||||
}
|
||||
|
||||
namespace {
|
||||
class DSARefChecker : public StmtVisitor<DSARefChecker, bool> {
|
||||
DSAStackTy *Stack;
|
||||
|
||||
public:
|
||||
bool VisitDeclRefExpr(DeclRefExpr *E) {
|
||||
if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) {
|
||||
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD);
|
||||
if (DVar.CKind == OMPC_shared && !DVar.RefExpr)
|
||||
return false;
|
||||
if (DVar.CKind != OMPC_unknown)
|
||||
return true;
|
||||
DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA(VD, OMPC_private);
|
||||
DSAStackTy::DSAVarData DVarFirstprivate =
|
||||
Stack->hasDSA(VD, OMPC_firstprivate);
|
||||
DSAStackTy::DSAVarData DVarReduction = Stack->hasDSA(VD, OMPC_reduction);
|
||||
if (DVarPrivate.CKind != OMPC_unknown ||
|
||||
DVarFirstprivate.CKind != OMPC_unknown ||
|
||||
DVarReduction.CKind != OMPC_unknown)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool VisitStmt(Stmt *S) {
|
||||
for (auto Child : S->children()) {
|
||||
if (Child && Visit(Child))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
DSARefChecker(DSAStackTy *S) : Stack(S) {}
|
||||
};
|
||||
}
|
||||
|
||||
OMPClause *Sema::ActOnOpenMPReductionClause(
|
||||
ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation ColonLoc, SourceLocation EndLoc,
|
||||
CXXScopeSpec &ReductionIdScopeSpec,
|
||||
const DeclarationNameInfo &ReductionId) {
|
||||
// TODO: Allow scope specification search when 'declare reduction' is
|
||||
// supported.
|
||||
assert(ReductionIdScopeSpec.isEmpty() &&
|
||||
"No support for scoped reduction identifiers yet.");
|
||||
|
||||
auto DN = ReductionId.getName();
|
||||
auto OOK = DN.getCXXOverloadedOperator();
|
||||
BinaryOperatorKind BOK = BO_Comma;
|
||||
|
||||
// OpenMP [2.14.3.6, reduction clause]
|
||||
// C
|
||||
// reduction-identifier is either an identifier or one of the following
|
||||
// operators: +, -, *, &, |, ^, && and ||
|
||||
// C++
|
||||
// reduction-identifier is either an id-expression or one of the following
|
||||
// operators: +, -, *, &, |, ^, && and ||
|
||||
// FIXME: Only 'min' and 'max' identifiers are supported for now.
|
||||
switch (OOK) {
|
||||
case OO_Plus:
|
||||
case OO_Minus:
|
||||
BOK = BO_AddAssign;
|
||||
break;
|
||||
case OO_Star:
|
||||
BOK = BO_MulAssign;
|
||||
break;
|
||||
case OO_Amp:
|
||||
BOK = BO_AndAssign;
|
||||
break;
|
||||
case OO_Pipe:
|
||||
BOK = BO_OrAssign;
|
||||
break;
|
||||
case OO_Caret:
|
||||
BOK = BO_XorAssign;
|
||||
break;
|
||||
case OO_AmpAmp:
|
||||
BOK = BO_LAnd;
|
||||
break;
|
||||
case OO_PipePipe:
|
||||
BOK = BO_LOr;
|
||||
break;
|
||||
default:
|
||||
if (auto II = DN.getAsIdentifierInfo()) {
|
||||
if (II->isStr("max"))
|
||||
BOK = BO_GT;
|
||||
else if (II->isStr("min"))
|
||||
BOK = BO_LT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
SourceRange ReductionIdRange;
|
||||
if (ReductionIdScopeSpec.isValid()) {
|
||||
ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc());
|
||||
}
|
||||
ReductionIdRange.setEnd(ReductionId.getEndLoc());
|
||||
if (BOK == BO_Comma) {
|
||||
// Not allowed reduction identifier is found.
|
||||
Diag(ReductionId.getLocStart(), diag::err_omp_unknown_reduction_identifier)
|
||||
<< ReductionIdRange;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SmallVector<Expr *, 8> Vars;
|
||||
for (auto RefExpr : VarList) {
|
||||
assert(RefExpr && "nullptr expr in OpenMP reduction clause.");
|
||||
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
|
||||
// It will be analyzed later.
|
||||
Vars.push_back(RefExpr);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
|
||||
RefExpr->isInstantiationDependent() ||
|
||||
RefExpr->containsUnexpandedParameterPack()) {
|
||||
// It will be analyzed later.
|
||||
Vars.push_back(RefExpr);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto ELoc = RefExpr->getExprLoc();
|
||||
auto ERange = RefExpr->getSourceRange();
|
||||
// OpenMP [2.1, C/C++]
|
||||
// A list item is a variable or array section, subject to the restrictions
|
||||
// specified in Section 2.4 on page 42 and in each of the sections
|
||||
// describing clauses and directives for which a list appears.
|
||||
// OpenMP [2.14.3.3, Restrictions, p.1]
|
||||
// A variable that is part of another variable (as an array or
|
||||
// structure element) cannot appear in a private clause.
|
||||
auto DE = dyn_cast<DeclRefExpr>(RefExpr);
|
||||
if (!DE || !isa<VarDecl>(DE->getDecl())) {
|
||||
Diag(ELoc, diag::err_omp_expected_var_name) << ERange;
|
||||
continue;
|
||||
}
|
||||
auto D = DE->getDecl();
|
||||
auto VD = cast<VarDecl>(D);
|
||||
auto Type = VD->getType();
|
||||
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
|
||||
// A variable that appears in a private clause must not have an incomplete
|
||||
// type or a reference type.
|
||||
if (RequireCompleteType(ELoc, Type,
|
||||
diag::err_omp_reduction_incomplete_type))
|
||||
continue;
|
||||
// OpenMP [2.14.3.6, reduction clause, Restrictions]
|
||||
// Arrays may not appear in a reduction clause.
|
||||
if (Type.getNonReferenceType()->isArrayType()) {
|
||||
Diag(ELoc, diag::err_omp_reduction_type_array) << Type << ERange;
|
||||
bool IsDecl =
|
||||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
|
||||
Diag(VD->getLocation(),
|
||||
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
|
||||
<< VD;
|
||||
continue;
|
||||
}
|
||||
// OpenMP [2.14.3.6, reduction clause, Restrictions]
|
||||
// A list item that appears in a reduction clause must not be
|
||||
// const-qualified.
|
||||
if (Type.getNonReferenceType().isConstant(Context)) {
|
||||
Diag(ELoc, diag::err_omp_const_variable)
|
||||
<< getOpenMPClauseName(OMPC_reduction) << Type << ERange;
|
||||
bool IsDecl =
|
||||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
|
||||
Diag(VD->getLocation(),
|
||||
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
|
||||
<< VD;
|
||||
continue;
|
||||
}
|
||||
// OpenMP [2.9.3.6, Restrictions, C/C++, p.4]
|
||||
// If a list-item is a reference type then it must bind to the same object
|
||||
// for all threads of the team.
|
||||
VarDecl *VDDef = VD->getDefinition();
|
||||
if (Type->isReferenceType() && VDDef) {
|
||||
DSARefChecker Check(DSAStack);
|
||||
if (Check.Visit(VDDef->getInit())) {
|
||||
Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange;
|
||||
Diag(VDDef->getLocation(), diag::note_defined_here) << VDDef;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// OpenMP [2.14.3.6, reduction clause, Restrictions]
|
||||
// The type of a list item that appears in a reduction clause must be valid
|
||||
// for the reduction-identifier. For a max or min reduction in C, the type
|
||||
// of the list item must be an allowed arithmetic data type: char, int,
|
||||
// float, double, or _Bool, possibly modified with long, short, signed, or
|
||||
// unsigned. For a max or min reduction in C++, the type of the list item
|
||||
// must be an allowed arithmetic data type: char, wchar_t, int, float,
|
||||
// double, or bool, possibly modified with long, short, signed, or unsigned.
|
||||
if ((BOK == BO_GT || BOK == BO_LT) &&
|
||||
!(Type->isScalarType() ||
|
||||
(getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
|
||||
Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
|
||||
<< getLangOpts().CPlusPlus;
|
||||
bool IsDecl =
|
||||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
|
||||
Diag(VD->getLocation(),
|
||||
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
|
||||
<< VD;
|
||||
continue;
|
||||
}
|
||||
if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) &&
|
||||
!getLangOpts().CPlusPlus && Type->isFloatingType()) {
|
||||
Diag(ELoc, diag::err_omp_clause_floating_type_arg);
|
||||
bool IsDecl =
|
||||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
|
||||
Diag(VD->getLocation(),
|
||||
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
|
||||
<< VD;
|
||||
continue;
|
||||
}
|
||||
bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
|
||||
getDiagnostics().setSuppressAllDiagnostics(true);
|
||||
ExprResult ReductionOp =
|
||||
BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK,
|
||||
RefExpr, RefExpr);
|
||||
getDiagnostics().setSuppressAllDiagnostics(Suppress);
|
||||
if (ReductionOp.isInvalid()) {
|
||||
Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type
|
||||
<< ReductionIdRange;
|
||||
bool IsDecl =
|
||||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
|
||||
Diag(VD->getLocation(),
|
||||
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
|
||||
<< VD;
|
||||
continue;
|
||||
}
|
||||
|
||||
// OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
|
||||
// in a Construct]
|
||||
// Variables with the predetermined data-sharing attributes may not be
|
||||
// listed in data-sharing attributes clauses, except for the cases
|
||||
// listed below. For these exceptions only, listing a predetermined
|
||||
// variable in a data-sharing attribute clause is allowed and overrides
|
||||
// the variable's predetermined data-sharing attributes.
|
||||
// OpenMP [2.14.3.6, Restrictions, p.3]
|
||||
// Any number of reduction clauses can be specified on the directive,
|
||||
// but a list item can appear only once in the reduction clauses for that
|
||||
// directive.
|
||||
DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD);
|
||||
if (DVar.CKind == OMPC_reduction) {
|
||||
Diag(ELoc, diag::err_omp_once_referenced)
|
||||
<< getOpenMPClauseName(OMPC_reduction);
|
||||
if (DVar.RefExpr) {
|
||||
Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
|
||||
}
|
||||
} else if (DVar.CKind != OMPC_unknown) {
|
||||
Diag(ELoc, diag::err_omp_wrong_dsa)
|
||||
<< getOpenMPClauseName(DVar.CKind)
|
||||
<< getOpenMPClauseName(OMPC_reduction);
|
||||
if (DVar.RefExpr) {
|
||||
Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
|
||||
<< getOpenMPClauseName(DVar.CKind);
|
||||
} else {
|
||||
Diag(VD->getLocation(), diag::note_omp_predetermined_dsa)
|
||||
<< getOpenMPClauseName(DVar.CKind);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// OpenMP [2.14.3.6, Restrictions, p.1]
|
||||
// A list item that appears in a reduction clause of a worksharing
|
||||
// construct must be shared in the parallel regions to which any of the
|
||||
// worksharing regions arising from the worksharing construct bind.
|
||||
// TODO Implement it later.
|
||||
|
||||
CXXRecordDecl *RD = getLangOpts().CPlusPlus
|
||||
? Type.getNonReferenceType()->getAsCXXRecordDecl()
|
||||
: nullptr;
|
||||
if (RD) {
|
||||
CXXConstructorDecl *CD = LookupDefaultConstructor(RD);
|
||||
PartialDiagnostic PD =
|
||||
PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
|
||||
if (!CD || CheckConstructorAccess(
|
||||
ELoc, CD, InitializedEntity::InitializeTemporary(Type),
|
||||
CD->getAccess(), PD) == AR_inaccessible ||
|
||||
CD->isDeleted()) {
|
||||
Diag(ELoc, diag::err_omp_required_method)
|
||||
<< getOpenMPClauseName(OMPC_reduction) << 0;
|
||||
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
||||
VarDecl::DeclarationOnly;
|
||||
Diag(VD->getLocation(),
|
||||
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
|
||||
<< VD;
|
||||
Diag(RD->getLocation(), diag::note_previous_decl) << RD;
|
||||
continue;
|
||||
}
|
||||
MarkFunctionReferenced(ELoc, CD);
|
||||
DiagnoseUseOfDecl(CD, ELoc);
|
||||
|
||||
CXXDestructorDecl *DD = RD->getDestructor();
|
||||
if (DD) {
|
||||
if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
|
||||
DD->isDeleted()) {
|
||||
Diag(ELoc, diag::err_omp_required_method)
|
||||
<< getOpenMPClauseName(OMPC_reduction) << 4;
|
||||
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
|
||||
VarDecl::DeclarationOnly;
|
||||
Diag(VD->getLocation(),
|
||||
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
|
||||
<< VD;
|
||||
Diag(RD->getLocation(), diag::note_previous_decl) << RD;
|
||||
continue;
|
||||
}
|
||||
MarkFunctionReferenced(ELoc, DD);
|
||||
DiagnoseUseOfDecl(DD, ELoc);
|
||||
}
|
||||
}
|
||||
|
||||
DSAStack->addDSA(VD, DE, OMPC_reduction);
|
||||
Vars.push_back(DE);
|
||||
}
|
||||
|
||||
if (Vars.empty())
|
||||
return nullptr;
|
||||
|
||||
return OMPReductionClause::Create(
|
||||
Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars,
|
||||
ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId);
|
||||
}
|
||||
|
||||
OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step,
|
||||
SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc,
|
||||
|
|
|
@ -1425,6 +1425,22 @@ public:
|
|||
EndLoc);
|
||||
}
|
||||
|
||||
/// \brief Build a new OpenMP 'reduction' clause.
|
||||
///
|
||||
/// By default, performs semantic analysis to build the new statement.
|
||||
/// Subclasses may override this routine to provide different behavior.
|
||||
OMPClause *RebuildOMPReductionClause(ArrayRef<Expr *> VarList,
|
||||
SourceLocation StartLoc,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation ColonLoc,
|
||||
SourceLocation EndLoc,
|
||||
CXXScopeSpec &ReductionIdScopeSpec,
|
||||
const DeclarationNameInfo &ReductionId) {
|
||||
return getSema().ActOnOpenMPReductionClause(
|
||||
VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec,
|
||||
ReductionId);
|
||||
}
|
||||
|
||||
/// \brief Build a new OpenMP 'linear' clause.
|
||||
///
|
||||
/// By default, performs semantic analysis to build the new OpenMP clause.
|
||||
|
@ -6348,10 +6364,8 @@ StmtResult TreeTransform<Derived>::TransformOMPExecutableDirective(
|
|||
I != E; ++I) {
|
||||
if (*I) {
|
||||
OMPClause *Clause = getDerived().TransformOMPClause(*I);
|
||||
if (!Clause) {
|
||||
return StmtError();
|
||||
}
|
||||
TClauses.push_back(Clause);
|
||||
if (Clause)
|
||||
TClauses.push_back(Clause);
|
||||
} else {
|
||||
TClauses.push_back(nullptr);
|
||||
}
|
||||
|
@ -6361,7 +6375,7 @@ StmtResult TreeTransform<Derived>::TransformOMPExecutableDirective(
|
|||
}
|
||||
StmtResult AssociatedStmt =
|
||||
getDerived().TransformStmt(D->getAssociatedStmt());
|
||||
if (AssociatedStmt.isInvalid()) {
|
||||
if (AssociatedStmt.isInvalid() || TClauses.size() != Clauses.size()) {
|
||||
return StmtError();
|
||||
}
|
||||
|
||||
|
@ -6508,6 +6522,31 @@ TreeTransform<Derived>::TransformOMPSharedClause(OMPSharedClause *C) {
|
|||
C->getLParenLoc(), C->getLocEnd());
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
OMPClause *
|
||||
TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause *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());
|
||||
}
|
||||
CXXScopeSpec ReductionIdScopeSpec;
|
||||
ReductionIdScopeSpec.Adopt(C->getQualifierLoc());
|
||||
|
||||
DeclarationNameInfo NameInfo = C->getNameInfo();
|
||||
if (NameInfo.getName()) {
|
||||
NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo);
|
||||
if (!NameInfo.getName())
|
||||
return nullptr;
|
||||
}
|
||||
return getDerived().RebuildOMPReductionClause(
|
||||
Vars, C->getLocStart(), C->getLParenLoc(), C->getColonLoc(),
|
||||
C->getLocEnd(), ReductionIdScopeSpec, NameInfo);
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
OMPClause *
|
||||
TreeTransform<Derived>::TransformOMPLinearClause(OMPLinearClause *C) {
|
||||
|
@ -10017,7 +10056,11 @@ TreeTransform<Derived>::TransformCapturedStmt(CapturedStmt *S) {
|
|||
}
|
||||
getSema().ActOnCapturedRegionStart(Loc, /*CurScope*/nullptr,
|
||||
S->getCapturedRegionKind(), Params);
|
||||
StmtResult Body = getDerived().TransformStmt(S->getCapturedStmt());
|
||||
StmtResult Body;
|
||||
{
|
||||
Sema::CompoundScopeRAII CompoundScope(getSema());
|
||||
Body = getDerived().TransformStmt(S->getCapturedStmt());
|
||||
}
|
||||
|
||||
if (Body.isInvalid()) {
|
||||
getSema().ActOnCapturedRegionError();
|
||||
|
|
|
@ -1703,6 +1703,9 @@ OMPClause *OMPClauseReader::readClause() {
|
|||
case OMPC_shared:
|
||||
C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]);
|
||||
break;
|
||||
case OMPC_reduction:
|
||||
C = OMPReductionClause::CreateEmpty(Context, Record[Idx++]);
|
||||
break;
|
||||
case OMPC_linear:
|
||||
C = OMPLinearClause::CreateEmpty(Context, Record[Idx++]);
|
||||
break;
|
||||
|
@ -1794,6 +1797,24 @@ void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) {
|
|||
C->setVarRefs(Vars);
|
||||
}
|
||||
|
||||
void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) {
|
||||
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
|
||||
C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
|
||||
NestedNameSpecifierLoc NNSL =
|
||||
Reader->Reader.ReadNestedNameSpecifierLoc(Reader->F, Record, Idx);
|
||||
DeclarationNameInfo DNI;
|
||||
Reader->ReadDeclarationNameInfo(DNI, Record, Idx);
|
||||
C->setQualifierLoc(NNSL);
|
||||
C->setNameInfo(DNI);
|
||||
|
||||
unsigned NumVars = C->varlist_size();
|
||||
SmallVector<Expr *, 16> Vars;
|
||||
Vars.reserve(NumVars);
|
||||
for (unsigned i = 0; i != NumVars; ++i)
|
||||
Vars.push_back(Reader->Reader.ReadSubExpr());
|
||||
C->setVarRefs(Vars);
|
||||
}
|
||||
|
||||
void OMPClauseReader::VisitOMPLinearClause(OMPLinearClause *C) {
|
||||
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
|
||||
C->setColonLoc(Reader->ReadSourceLocation(Record, Idx));
|
||||
|
|
|
@ -1735,6 +1735,16 @@ void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) {
|
|||
Writer->Writer.AddStmt(VE);
|
||||
}
|
||||
|
||||
void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) {
|
||||
Record.push_back(C->varlist_size());
|
||||
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
|
||||
Writer->Writer.AddSourceLocation(C->getColonLoc(), Record);
|
||||
Writer->Writer.AddNestedNameSpecifierLoc(C->getQualifierLoc(), Record);
|
||||
Writer->Writer.AddDeclarationNameInfo(C->getNameInfo(), Record);
|
||||
for (auto *VE : C->varlists())
|
||||
Writer->Writer.AddStmt(VE);
|
||||
}
|
||||
|
||||
void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) {
|
||||
Record.push_back(C->varlist_size());
|
||||
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
|
||||
|
|
|
@ -35,9 +35,9 @@ T tmain(T argc, T *argv) {
|
|||
S<T> s;
|
||||
#pragma omp parallel
|
||||
a=2;
|
||||
#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (argc > 0) num_threads(C) copyin(S<T>::TS) proc_bind(master)
|
||||
#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (argc > 0) num_threads(C) copyin(S<T>::TS) proc_bind(master) reduction(+:c) reduction(max:e)
|
||||
foo();
|
||||
#pragma omp parallel if (C) num_threads(s) proc_bind(close)
|
||||
#pragma omp parallel if (C) num_threads(s) proc_bind(close) reduction(^:e, f) reduction(&& : g)
|
||||
foo();
|
||||
return 0;
|
||||
}
|
||||
|
@ -48,9 +48,9 @@ T tmain(T argc, T *argv) {
|
|||
// CHECK-NEXT: S<int> s;
|
||||
// CHECK-NEXT: #pragma omp parallel
|
||||
// CHECK-NEXT: a = 2;
|
||||
// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(5) copyin(S<int>::TS) proc_bind(master)
|
||||
// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(5) copyin(S<int>::TS) proc_bind(master) reduction(+: c) reduction(max: e)
|
||||
// CHECK-NEXT: foo()
|
||||
// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) proc_bind(close)
|
||||
// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) proc_bind(close) reduction(^: e,f) reduction(&&: g)
|
||||
// CHECK-NEXT: foo()
|
||||
// CHECK: template <typename T = long, int C = 1> long tmain(long argc, long *argv) {
|
||||
// CHECK-NEXT: long b = argc, c, d, e, f, g;
|
||||
|
@ -58,9 +58,9 @@ T tmain(T argc, T *argv) {
|
|||
// CHECK-NEXT: S<long> s;
|
||||
// CHECK-NEXT: #pragma omp parallel
|
||||
// CHECK-NEXT: a = 2;
|
||||
// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(1) copyin(S<long>::TS) proc_bind(master)
|
||||
// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(1) copyin(S<long>::TS) proc_bind(master) reduction(+: c) reduction(max: e)
|
||||
// CHECK-NEXT: foo()
|
||||
// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) proc_bind(close)
|
||||
// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) proc_bind(close) reduction(^: e,f) reduction(&&: g)
|
||||
// CHECK-NEXT: foo()
|
||||
// CHECK: template <typename T, int C> T tmain(T argc, T *argv) {
|
||||
// CHECK-NEXT: T b = argc, c, d, e, f, g;
|
||||
|
@ -68,9 +68,9 @@ T tmain(T argc, T *argv) {
|
|||
// CHECK-NEXT: S<T> s;
|
||||
// CHECK-NEXT: #pragma omp parallel
|
||||
// CHECK-NEXT: a = 2;
|
||||
// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(C) copyin(S<T>::TS) proc_bind(master)
|
||||
// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(argc > 0) num_threads(C) copyin(S<T>::TS) proc_bind(master) reduction(+: c) reduction(max: e)
|
||||
// CHECK-NEXT: foo()
|
||||
// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) proc_bind(close)
|
||||
// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) proc_bind(close) reduction(^: e,f) reduction(&&: g)
|
||||
// CHECK-NEXT: foo()
|
||||
|
||||
enum Enum { };
|
||||
|
@ -86,8 +86,8 @@ int main (int argc, char **argv) {
|
|||
// CHECK-NEXT: #pragma omp parallel
|
||||
a=2;
|
||||
// CHECK-NEXT: a = 2;
|
||||
#pragma omp parallel default(none), private(argc,b) firstprivate(argv) if (argc > 0) num_threads(ee) copyin(a) proc_bind(spread)
|
||||
// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(argc > 0) num_threads(ee) copyin(a) proc_bind(spread)
|
||||
#pragma omp parallel default(none), private(argc,b) firstprivate(argv) if (argc > 0) num_threads(ee) copyin(a) proc_bind(spread) reduction(| : c, d) reduction(* : e)
|
||||
// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) if(argc > 0) num_threads(ee) copyin(a) proc_bind(spread) reduction(|: c,d) reduction(*: e)
|
||||
foo();
|
||||
// CHECK-NEXT: foo();
|
||||
return tmain<int, 5>(b, &b) + tmain<long, 1>(x, &x);
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -ferror-limit 100 -o - %s
|
||||
|
||||
void foo() {
|
||||
}
|
||||
|
||||
bool foobool(int argc) {
|
||||
return argc;
|
||||
}
|
||||
|
||||
struct S1; // expected-note {{declared here}} expected-note 4 {{forward declaration of 'S1'}}
|
||||
extern S1 a;
|
||||
class S2 {
|
||||
mutable int a;
|
||||
S2 &operator +=(const S2 &arg) {return (*this);}
|
||||
public:
|
||||
S2():a(0) { }
|
||||
S2(S2 &s2):a(s2.a) { }
|
||||
static float S2s; // expected-note 2 {{predetermined as shared}}
|
||||
static const float S2sc;
|
||||
};
|
||||
const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}}
|
||||
S2 b; // expected-note 2 {{'b' defined here}}
|
||||
const S2 ba[5]; // expected-note 2 {{'ba' defined here}}
|
||||
class S3 {
|
||||
int a;
|
||||
public:
|
||||
S3():a(0) { }
|
||||
S3(const S3 &s3):a(s3.a) { }
|
||||
S3 operator +=(const S3 &arg1) {return arg1;}
|
||||
};
|
||||
int operator +=(const S3 &arg1, const S3 &arg2) {return 5;}
|
||||
S3 c; // expected-note 2 {{'c' defined here}}
|
||||
const S3 ca[5]; // expected-note 2 {{'ca' defined here}}
|
||||
extern const int f; // expected-note 4 {{'f' declared here}}
|
||||
class S4 { // expected-note {{'S4' declared here}}
|
||||
int a;
|
||||
S4();
|
||||
S4(const S4 &s4);
|
||||
S4 &operator +=(const S4 &arg) {return (*this);}
|
||||
public:
|
||||
S4(int v):a(v) { }
|
||||
};
|
||||
S4 &operator &=(S4 &arg1, S4 &arg2) {return arg1;}
|
||||
class S5 {
|
||||
int a;
|
||||
S5():a(0) {}
|
||||
S5(const S5 &s5):a(s5.a) { }
|
||||
S5 &operator +=(const S5 &arg);
|
||||
public:
|
||||
S5(int v):a(v) { }
|
||||
};
|
||||
class S6 {
|
||||
int a;
|
||||
public:
|
||||
S6():a(6){ }
|
||||
operator int() { return 6; }
|
||||
} o; // expected-note 2 {{'o' defined here}}
|
||||
|
||||
S3 h, k;
|
||||
#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}}
|
||||
|
||||
template <class T> // expected-note {{declared here}}
|
||||
T tmain(T argc) { // expected-note 2 {{'argc' defined here}}
|
||||
const T d = T(); // expected-note 4 {{'d' defined here}}
|
||||
const T da[5] = { T() }; // expected-note 2 {{'da' defined here}}
|
||||
T qa[5] = { T() };
|
||||
T i;
|
||||
T &j = i; // expected-note 4 {{'j' defined here}}
|
||||
S3 &p = k; // expected-note 2 {{'p' defined here}}
|
||||
const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}}
|
||||
T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}}
|
||||
T fl; // expected-note {{'fl' defined here}}
|
||||
#pragma omp parallel reduction // expected-error {{expected '(' after 'reduction'}}
|
||||
foo();
|
||||
#pragma omp parallel reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
|
||||
foo();
|
||||
#pragma omp parallel reduction ( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||
foo();
|
||||
#pragma omp parallel reduction () // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (&: argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (| :argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{variable of type 'float' is not valid for specified reduction operation}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (|| :argc ? i : argc) // expected-error 2 {{expected variable name}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (foo:argc) //expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (&& :argc)
|
||||
foo();
|
||||
#pragma omp parallel reduction (^ : T) // expected-error {{'T' does not refer to a value}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 3 {{const-qualified variable cannot be reduction}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified variable cannot be reduction}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (max : qa[1]) // expected-error 2 {{expected variable name}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(+ : ba) // expected-error {{a reduction variable with array type 'const S2 [5]'}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(* : ca) // expected-error {{a reduction variable with array type 'const S3 [5]'}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}} expected-error {{a reduction variable with array type 'const float [5]'}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
|
||||
foo();
|
||||
#pragma omp parallel private(i), reduction(+ : j), reduction(+:q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
|
||||
foo();
|
||||
#pragma omp parallel private(k)
|
||||
#pragma omp parallel reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(+ : p), reduction(+ : p) // expected-error 3 {{variable can appear only once in OpenMP 'reduction' clause}} expected-note 3 {{previously referenced here}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(+ : r) // expected-error 2 {{const-qualified variable cannot be reduction}}
|
||||
foo();
|
||||
#pragma omp parallel shared(i)
|
||||
#pragma omp parallel reduction(min : i)
|
||||
#pragma omp parallel reduction(max : j) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
|
||||
foo();
|
||||
|
||||
return T();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const int d = 5; // expected-note 2 {{'d' defined here}}
|
||||
const int da[5] = { 0 }; // expected-note {{'da' defined here}}
|
||||
int qa[5] = { 0 };
|
||||
S4 e(4); // expected-note {{'e' defined here}}
|
||||
S5 g(5); // expected-note {{'g' defined here}}
|
||||
int i;
|
||||
int &j = i; // expected-note 2 {{'j' defined here}}
|
||||
S3 &p = k; // expected-note 2 {{'p' defined here}}
|
||||
const int &r = da[i]; // expected-note {{'r' defined here}}
|
||||
int &q = qa[i]; // expected-note {{'q' defined here}}
|
||||
float fl; // expected-note {{'fl' defined here}}
|
||||
#pragma omp parallel reduction // expected-error {{expected '(' after 'reduction'}}
|
||||
foo();
|
||||
#pragma omp parallel reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp parallel' are ignored}}
|
||||
foo();
|
||||
#pragma omp parallel reduction ( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||
foo();
|
||||
#pragma omp parallel reduction () // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (foo: argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (| :argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (|| :argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (~:argc) // expected-error {{expected unqualified-id}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (&& :argc)
|
||||
foo();
|
||||
#pragma omp parallel reduction (^ : S1) // expected-error {{'S1' does not refer to a value}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (+ : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{const-qualified variable cannot be reduction}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (min : a, b, c, d, f) // expected-error {{reduction variable with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified variable cannot be reduction}}
|
||||
foo();
|
||||
#pragma omp parallel reduction (max : argv[1]) // expected-error {{expected variable name}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(+ : ba) // expected-error {{a reduction variable with array type 'const S2 [5]'}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(* : ca) // expected-error {{a reduction variable with array type 'const S3 [5]'}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(- : da) // expected-error {{a reduction variable with array type 'const int [5]'}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(^ : fl) // expected-error {{variable of type 'float' is not valid for specified reduction operation}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(&& : S2::S2sc) // expected-error {{const-qualified variable cannot be reduction}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(& : e, g) // expected-error {{reduction variable must have an accessible, unambiguous default constructor}} expected-error {{variable of type 'S5' is not valid for specified reduction operation}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(+ : o) // expected-error {{variable of type 'class S6' is not valid for specified reduction operation}}
|
||||
foo();
|
||||
#pragma omp parallel private(i), reduction(+ : j), reduction(+:q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
|
||||
foo();
|
||||
#pragma omp parallel private(k)
|
||||
#pragma omp parallel reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}}
|
||||
foo();
|
||||
#pragma omp parallel reduction(+ : r) // expected-error {{const-qualified variable cannot be reduction}}
|
||||
foo();
|
||||
#pragma omp parallel shared(i)
|
||||
#pragma omp parallel reduction(min : i)
|
||||
#pragma omp parallel reduction(max : j) // expected-error {{argument of OpenMP clause 'reduction' must reference the same object in all threads}}
|
||||
foo();
|
||||
|
||||
return tmain(argc) + tmain(fl); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<float>' requested here}}
|
||||
}
|
|
@ -52,13 +52,14 @@ template<int L, class T, class N> T test_template(T* arr, N num) {
|
|||
// expected-error@+1 {{argument to 'aligned' clause must be a positive integer value}}
|
||||
#pragma omp simd aligned(arr:L)
|
||||
for (i = 0; i < num; ++i) {
|
||||
T cur = arr[ind2];
|
||||
T cur = arr[(int)ind2];
|
||||
ind2 += L;
|
||||
sum += cur;
|
||||
}
|
||||
// expected-error@+1 {{argument of aligned clause should be array, pointer, reference to array or reference to pointer, not 'int'}}
|
||||
#pragma omp simd aligned(num:4)
|
||||
for (i = 0; i < num; ++i);
|
||||
return T();
|
||||
}
|
||||
|
||||
template<int LEN> int test_warn() {
|
||||
|
|
|
@ -50,10 +50,11 @@ template<int L, class T, class N> T test_template(T* arr, N num) {
|
|||
// expected-error@+1 {{argument of a linear clause should be of integral or pointer type}}
|
||||
#pragma omp simd linear(ind2:L)
|
||||
for (i = 0; i < num; ++i) {
|
||||
T cur = arr[ind2];
|
||||
T cur = arr[(int)ind2];
|
||||
ind2 += L;
|
||||
sum += cur;
|
||||
}
|
||||
return T();
|
||||
}
|
||||
|
||||
template<int LEN> int test_warn() {
|
||||
|
|
|
@ -1963,6 +1963,9 @@ void OMPClauseEnqueue::VisitOMPLastprivateClause(
|
|||
void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) {
|
||||
VisitOMPClauseList(C);
|
||||
}
|
||||
void OMPClauseEnqueue::VisitOMPReductionClause(const OMPReductionClause *C) {
|
||||
VisitOMPClauseList(C);
|
||||
}
|
||||
void OMPClauseEnqueue::VisitOMPLinearClause(const OMPLinearClause *C) {
|
||||
VisitOMPClauseList(C);
|
||||
Visitor->AddStmt(C->getStep());
|
||||
|
|
Loading…
Reference in New Issue