forked from OSchip/llvm-project
[OPENMP 4.0] Support for 'uniform' clause in 'declare simd' directive.
OpenMP 4.0 defines clause 'uniform' in 'declare simd' directive: 'uniform' '(' <argument-list> ')' The uniform clause declares one or more arguments to have an invariant value for all concurrent invocations of the function in the execution of a single SIMD loop. The special this pointer can be used as if was one of the arguments to the function in any of the linear, aligned, or uniform clauses. llvm-svn: 266041
This commit is contained in:
parent
94f58e79ae
commit
e48a5fc56d
|
@ -2517,6 +2517,7 @@ bool RecursiveASTVisitor<Derived>::TraverseOMPClause(OMPClause *C) {
|
|||
break;
|
||||
#include "clang/Basic/OpenMPKinds.def"
|
||||
case OMPC_threadprivate:
|
||||
case OMPC_uniform:
|
||||
case OMPC_unknown:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -2276,7 +2276,7 @@ def OMPDeclareSimdDecl : Attr {
|
|||
EnumArgument<"BranchState", "BranchStateTy",
|
||||
[ "", "inbranch", "notinbranch" ],
|
||||
[ "BS_Undefined", "BS_Inbranch", "BS_Notinbranch" ]>,
|
||||
ExprArgument<"Simdlen">
|
||||
ExprArgument<"Simdlen">, VariadicExprArgument<"Uniforms">
|
||||
];
|
||||
let AdditionalMembers = [{
|
||||
void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy)
|
||||
|
@ -2288,6 +2288,16 @@ def OMPDeclareSimdDecl : Attr {
|
|||
E->printPretty(OS, nullptr, Policy);
|
||||
OS << ") ";
|
||||
}
|
||||
if (uniforms_size() > 0) {
|
||||
OS << "uniform";
|
||||
StringRef Sep = "(";
|
||||
for (auto *E : uniforms()) {
|
||||
OS << Sep;
|
||||
E->printPretty(OS, nullptr, Policy);
|
||||
Sep = ", ";
|
||||
}
|
||||
OS << ") ";
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -8180,6 +8180,8 @@ def err_omp_ordered_simd : Error<
|
|||
"'ordered' clause with a parameter can not be specified in '#pragma omp %0' directive">;
|
||||
def err_omp_variable_in_map_and_dsa : Error<
|
||||
"%0 variable cannot be in a map clause in '#pragma omp %1' directive">;
|
||||
def err_omp_param_or_this_in_clause : Error<
|
||||
"expected reference to one of the parameters of function %0%select{| or 'this'}1">;
|
||||
} // end of OpenMP category
|
||||
|
||||
let CategoryName = "Related Result Type Issue" in {
|
||||
|
|
|
@ -35,6 +35,7 @@ enum OpenMPClauseKind {
|
|||
OMPC_##Name,
|
||||
#include "clang/Basic/OpenMPKinds.def"
|
||||
OMPC_threadprivate,
|
||||
OMPC_uniform,
|
||||
OMPC_unknown
|
||||
};
|
||||
|
||||
|
|
|
@ -2528,6 +2528,25 @@ public:
|
|||
/// constructs.
|
||||
/// \param RLoc Returned location of right paren.
|
||||
ExprResult ParseOpenMPParensExpr(StringRef ClauseName, SourceLocation &RLoc);
|
||||
|
||||
/// Data used for parsing list of variables in OpenMP clauses.
|
||||
struct OpenMPVarListDataTy {
|
||||
Expr *TailExpr = nullptr;
|
||||
SourceLocation ColonLoc;
|
||||
CXXScopeSpec ReductionIdScopeSpec;
|
||||
DeclarationNameInfo ReductionId;
|
||||
OpenMPDependClauseKind DepKind = OMPC_DEPEND_unknown;
|
||||
OpenMPLinearClauseKind LinKind = OMPC_LINEAR_val;
|
||||
OpenMPMapClauseKind MapTypeModifier = OMPC_MAP_unknown;
|
||||
OpenMPMapClauseKind MapType = OMPC_MAP_unknown;
|
||||
bool IsMapTypeImplicit = false;
|
||||
SourceLocation DepLinMapLoc;
|
||||
};
|
||||
|
||||
/// Parses clauses with list.
|
||||
bool ParseOpenMPVarList(OpenMPDirectiveKind DKind, OpenMPClauseKind Kind,
|
||||
SmallVectorImpl<Expr *> &Vars,
|
||||
OpenMPVarListDataTy &Data);
|
||||
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
||||
bool AllowDestructorName,
|
||||
bool AllowConstructorName,
|
||||
|
|
|
@ -8110,10 +8110,9 @@ public:
|
|||
|
||||
/// \brief Called on well-formed '\#pragma omp declare simd' after parsing of
|
||||
/// the associated method/function.
|
||||
DeclGroupPtrTy
|
||||
ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
|
||||
OMPDeclareSimdDeclAttr::BranchStateTy BS,
|
||||
Expr *Simdlen, SourceRange SR);
|
||||
DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective(
|
||||
DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS,
|
||||
Expr *Simdlen, ArrayRef<Expr *> Uniforms, SourceRange SR);
|
||||
|
||||
OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
|
||||
Expr *Expr,
|
||||
|
|
|
@ -86,6 +86,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
|
|||
case OMPC_hint:
|
||||
case OMPC_defaultmap:
|
||||
case OMPC_unknown:
|
||||
case OMPC_uniform:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -146,6 +147,7 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
|
|||
case OMPC_hint:
|
||||
case OMPC_defaultmap:
|
||||
case OMPC_unknown:
|
||||
case OMPC_uniform:
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) {
|
|||
return llvm::StringSwitch<OpenMPClauseKind>(Str)
|
||||
#define OPENMP_CLAUSE(Name, Class) .Case(#Name, OMPC_##Name)
|
||||
#include "clang/Basic/OpenMPKinds.def"
|
||||
.Case("uniform", OMPC_uniform)
|
||||
.Default(OMPC_unknown);
|
||||
}
|
||||
|
||||
|
@ -67,6 +68,8 @@ const char *clang::getOpenMPClauseName(OpenMPClauseKind Kind) {
|
|||
case OMPC_##Name: \
|
||||
return #Name;
|
||||
#include "clang/Basic/OpenMPKinds.def"
|
||||
case OMPC_uniform:
|
||||
return "uniform";
|
||||
case OMPC_threadprivate:
|
||||
return "threadprivate or thread local";
|
||||
}
|
||||
|
@ -158,6 +161,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
|
|||
case OMPC_nogroup:
|
||||
case OMPC_num_tasks:
|
||||
case OMPC_hint:
|
||||
case OMPC_uniform:
|
||||
break;
|
||||
}
|
||||
llvm_unreachable("Invalid OpenMP simple clause kind");
|
||||
|
@ -292,6 +296,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
|
|||
case OMPC_nogroup:
|
||||
case OMPC_num_tasks:
|
||||
case OMPC_hint:
|
||||
case OMPC_uniform:
|
||||
break;
|
||||
}
|
||||
llvm_unreachable("Invalid OpenMP simple clause kind");
|
||||
|
|
|
@ -2975,6 +2975,7 @@ static void EmitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
|
|||
case OMPC_hint:
|
||||
case OMPC_dist_schedule:
|
||||
case OMPC_defaultmap:
|
||||
case OMPC_uniform:
|
||||
llvm_unreachable("Clause is not allowed in 'omp atomic'.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -333,9 +333,11 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
|
|||
/// clause:
|
||||
/// 'inbranch' | 'notinbranch'
|
||||
/// 'simdlen' '(' <expr> ')'
|
||||
/// { 'uniform' '(' <argument_list> ')' }
|
||||
static bool parseDeclareSimdClauses(Parser &P,
|
||||
OMPDeclareSimdDeclAttr::BranchStateTy &BS,
|
||||
ExprResult &SimdLen) {
|
||||
ExprResult &SimdLen,
|
||||
SmallVectorImpl<Expr *> &Uniforms) {
|
||||
SourceRange BSRange;
|
||||
const Token &Tok = P.getCurToken();
|
||||
bool IsError = false;
|
||||
|
@ -367,6 +369,13 @@ static bool parseDeclareSimdClauses(Parser &P,
|
|||
SimdLen = P.ParseOpenMPParensExpr(ClauseName, RLoc);
|
||||
if (SimdLen.isInvalid())
|
||||
IsError = true;
|
||||
} else if (ClauseName.equals("uniform")) {
|
||||
Parser::OpenMPVarListDataTy Data;
|
||||
|
||||
P.ConsumeToken();
|
||||
if (P.ParseOpenMPVarList(OMPD_declare_simd,
|
||||
getOpenMPClauseKind(ClauseName), Uniforms, Data))
|
||||
IsError = true;
|
||||
} else
|
||||
// TODO: add parsing of other clauses.
|
||||
break;
|
||||
|
@ -446,7 +455,8 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
|
|||
OMPDeclareSimdDeclAttr::BranchStateTy BS =
|
||||
OMPDeclareSimdDeclAttr::BS_Undefined;
|
||||
ExprResult Simdlen;
|
||||
bool IsError = parseDeclareSimdClauses(*this, BS, Simdlen);
|
||||
SmallVector<Expr *, 4> Uniforms;
|
||||
bool IsError = parseDeclareSimdClauses(*this, BS, Simdlen, Uniforms);
|
||||
// Need to check for extra tokens.
|
||||
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
|
||||
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
|
||||
|
@ -457,8 +467,8 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
|
|||
// Skip the last annot_pragma_openmp_end.
|
||||
SourceLocation EndLoc = ConsumeToken();
|
||||
if (!IsError)
|
||||
return Actions.ActOnOpenMPDeclareSimdDirective(Ptr, BS, Simdlen.get(),
|
||||
SourceRange(Loc, EndLoc));
|
||||
return Actions.ActOnOpenMPDeclareSimdDirective(
|
||||
Ptr, BS, Simdlen.get(), Uniforms, SourceRange(Loc, EndLoc));
|
||||
return Ptr;
|
||||
}
|
||||
|
||||
|
@ -526,8 +536,12 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
|
|||
//
|
||||
ConsumeToken();
|
||||
CachedTokens Toks;
|
||||
ConsumeAndStoreUntil(tok::annot_pragma_openmp_end, Toks,
|
||||
/*StopAtSemi=*/false, /*ConsumeFinalToken=*/true);
|
||||
while(Tok.isNot(tok::annot_pragma_openmp_end)) {
|
||||
Toks.push_back(Tok);
|
||||
ConsumeAnyToken();
|
||||
}
|
||||
Toks.push_back(Tok);
|
||||
ConsumeAnyToken();
|
||||
|
||||
DeclGroupPtrTy Ptr;
|
||||
if (Tok.is(tok::annot_pragma_openmp))
|
||||
|
@ -1081,6 +1095,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
|
|||
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
|
||||
break;
|
||||
case OMPC_threadprivate:
|
||||
case OMPC_uniform:
|
||||
Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind)
|
||||
<< getOpenMPDirectiveName(DKind);
|
||||
SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
|
||||
|
@ -1402,6 +1417,210 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
|
|||
TemplateKWLoc, ReductionId);
|
||||
}
|
||||
|
||||
/// Parses clauses with list.
|
||||
bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
|
||||
OpenMPClauseKind Kind,
|
||||
SmallVectorImpl<Expr *> &Vars,
|
||||
OpenMPVarListDataTy &Data) {
|
||||
UnqualifiedId UnqualifiedReductionId;
|
||||
bool InvalidReductionId = false;
|
||||
bool MapTypeModifierSpecified = false;
|
||||
|
||||
// Parse '('.
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
|
||||
if (T.expectAndConsume(diag::err_expected_lparen_after,
|
||||
getOpenMPClauseName(Kind)))
|
||||
return true;
|
||||
|
||||
bool NeedRParenForLinear = false;
|
||||
BalancedDelimiterTracker LinearT(*this, tok::l_paren,
|
||||
tok::annot_pragma_openmp_end);
|
||||
// Handle reduction-identifier for reduction clause.
|
||||
if (Kind == OMPC_reduction) {
|
||||
ColonProtectionRAIIObject ColonRAII(*this);
|
||||
if (getLangOpts().CPlusPlus)
|
||||
ParseOptionalCXXScopeSpecifier(Data.ReductionIdScopeSpec,
|
||||
/*ObjectType=*/nullptr,
|
||||
/*EnteringContext=*/false);
|
||||
InvalidReductionId = ParseReductionId(*this, Data.ReductionIdScopeSpec,
|
||||
UnqualifiedReductionId);
|
||||
if (InvalidReductionId) {
|
||||
SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
|
||||
StopBeforeMatch);
|
||||
}
|
||||
if (Tok.is(tok::colon))
|
||||
Data.ColonLoc = ConsumeToken();
|
||||
else
|
||||
Diag(Tok, diag::warn_pragma_expected_colon) << "reduction identifier";
|
||||
if (!InvalidReductionId)
|
||||
Data.ReductionId =
|
||||
Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId);
|
||||
} else if (Kind == OMPC_depend) {
|
||||
// Handle dependency type for depend clause.
|
||||
ColonProtectionRAIIObject ColonRAII(*this);
|
||||
Data.DepKind =
|
||||
static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType(
|
||||
Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""));
|
||||
Data.DepLinMapLoc = Tok.getLocation();
|
||||
|
||||
if (Data.DepKind == OMPC_DEPEND_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.DepKind == OMPC_DEPEND_source) {
|
||||
// Parse ')'.
|
||||
T.consumeClose();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (Tok.is(tok::colon))
|
||||
Data.ColonLoc = ConsumeToken();
|
||||
else {
|
||||
Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren
|
||||
: diag::warn_pragma_expected_colon)
|
||||
<< "dependency type";
|
||||
}
|
||||
} else if (Kind == OMPC_linear) {
|
||||
// Try to parse modifier if any.
|
||||
if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) {
|
||||
Data.LinKind = static_cast<OpenMPLinearClauseKind>(
|
||||
getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)));
|
||||
Data.DepLinMapLoc = ConsumeToken();
|
||||
LinearT.consumeOpen();
|
||||
NeedRParenForLinear = true;
|
||||
}
|
||||
} else if (Kind == OMPC_map) {
|
||||
// Handle map type for map clause.
|
||||
ColonProtectionRAIIObject ColonRAII(*this);
|
||||
|
||||
/// The map clause modifier token can be either a identifier or the C++
|
||||
/// delete keyword.
|
||||
auto &&IsMapClauseModifierToken = [](const Token &Tok) -> bool {
|
||||
return Tok.isOneOf(tok::identifier, tok::kw_delete);
|
||||
};
|
||||
|
||||
// The first identifier may be a list item, a map-type or a
|
||||
// map-type-modifier. The map modifier can also be delete which has the same
|
||||
// spelling of the C++ delete keyword.
|
||||
Data.MapType =
|
||||
IsMapClauseModifierToken(Tok)
|
||||
? static_cast<OpenMPMapClauseKind>(
|
||||
getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)))
|
||||
: OMPC_MAP_unknown;
|
||||
Data.DepLinMapLoc = Tok.getLocation();
|
||||
bool ColonExpected = false;
|
||||
|
||||
if (IsMapClauseModifierToken(Tok)) {
|
||||
if (PP.LookAhead(0).is(tok::colon)) {
|
||||
if (Data.MapType == OMPC_MAP_unknown)
|
||||
Diag(Tok, diag::err_omp_unknown_map_type);
|
||||
else if (Data.MapType == OMPC_MAP_always)
|
||||
Diag(Tok, diag::err_omp_map_type_missing);
|
||||
ConsumeToken();
|
||||
} else if (PP.LookAhead(0).is(tok::comma)) {
|
||||
if (IsMapClauseModifierToken(PP.LookAhead(1)) &&
|
||||
PP.LookAhead(2).is(tok::colon)) {
|
||||
Data.MapTypeModifier = Data.MapType;
|
||||
if (Data.MapTypeModifier != OMPC_MAP_always) {
|
||||
Diag(Tok, diag::err_omp_unknown_map_type_modifier);
|
||||
Data.MapTypeModifier = OMPC_MAP_unknown;
|
||||
} else
|
||||
MapTypeModifierSpecified = true;
|
||||
|
||||
ConsumeToken();
|
||||
ConsumeToken();
|
||||
|
||||
Data.MapType =
|
||||
IsMapClauseModifierToken(Tok)
|
||||
? static_cast<OpenMPMapClauseKind>(
|
||||
getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)))
|
||||
: OMPC_MAP_unknown;
|
||||
if (Data.MapType == OMPC_MAP_unknown ||
|
||||
Data.MapType == OMPC_MAP_always)
|
||||
Diag(Tok, diag::err_omp_unknown_map_type);
|
||||
ConsumeToken();
|
||||
} else {
|
||||
Data.MapType = OMPC_MAP_tofrom;
|
||||
Data.IsMapTypeImplicit = true;
|
||||
}
|
||||
} else {
|
||||
Data.MapType = OMPC_MAP_tofrom;
|
||||
Data.IsMapTypeImplicit = true;
|
||||
}
|
||||
} else {
|
||||
Data.MapType = OMPC_MAP_tofrom;
|
||||
Data.IsMapTypeImplicit = true;
|
||||
}
|
||||
|
||||
if (Tok.is(tok::colon))
|
||||
Data.ColonLoc = ConsumeToken();
|
||||
else if (ColonExpected)
|
||||
Diag(Tok, diag::warn_pragma_expected_colon) << "map type";
|
||||
}
|
||||
|
||||
bool IsComma =
|
||||
(Kind != OMPC_reduction && Kind != OMPC_depend && Kind != OMPC_map) ||
|
||||
(Kind == OMPC_reduction && !InvalidReductionId) ||
|
||||
(Kind == OMPC_map && Data.MapType != OMPC_MAP_unknown &&
|
||||
(!MapTypeModifierSpecified ||
|
||||
Data.MapTypeModifier == OMPC_MAP_always)) ||
|
||||
(Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown);
|
||||
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))) {
|
||||
ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
|
||||
// Parse variable
|
||||
ExprResult VarExpr =
|
||||
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
|
||||
if (VarExpr.isUsable())
|
||||
Vars.push_back(VarExpr.get());
|
||||
else {
|
||||
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
||||
StopBeforeMatch);
|
||||
}
|
||||
// Skip ',' if any
|
||||
IsComma = Tok.is(tok::comma);
|
||||
if (IsComma)
|
||||
ConsumeToken();
|
||||
else if (Tok.isNot(tok::r_paren) &&
|
||||
Tok.isNot(tok::annot_pragma_openmp_end) &&
|
||||
(!MayHaveTail || Tok.isNot(tok::colon)))
|
||||
Diag(Tok, diag::err_omp_expected_punc)
|
||||
<< ((Kind == OMPC_flush) ? getOpenMPDirectiveName(OMPD_flush)
|
||||
: getOpenMPClauseName(Kind))
|
||||
<< (Kind == OMPC_flush);
|
||||
}
|
||||
|
||||
// Parse ')' for linear clause with modifier.
|
||||
if (NeedRParenForLinear)
|
||||
LinearT.consumeClose();
|
||||
|
||||
// Parse ':' linear-step (or ':' alignment).
|
||||
const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);
|
||||
if (MustHaveTail) {
|
||||
Data.ColonLoc = Tok.getLocation();
|
||||
SourceLocation ELoc = ConsumeToken();
|
||||
ExprResult Tail = ParseAssignmentExpression();
|
||||
Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc);
|
||||
if (Tail.isUsable())
|
||||
Data.TailExpr = Tail.get();
|
||||
else
|
||||
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
||||
StopBeforeMatch);
|
||||
}
|
||||
|
||||
// Parse ')'.
|
||||
T.consumeClose();
|
||||
if ((Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown &&
|
||||
Vars.empty()) ||
|
||||
(Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) ||
|
||||
(MustHaveTail && !Data.TailExpr) || InvalidReductionId)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate',
|
||||
/// 'shared', 'copyin', 'copyprivate', 'flush' or 'reduction'.
|
||||
///
|
||||
|
@ -1437,226 +1656,16 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
|
|||
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;
|
||||
OpenMPDependClauseKind DepKind = OMPC_DEPEND_unknown;
|
||||
// OpenMP 4.1 [2.15.3.7, linear Clause]
|
||||
// If no modifier is specified it is assumed to be val.
|
||||
OpenMPLinearClauseKind LinearModifier = OMPC_LINEAR_val;
|
||||
OpenMPMapClauseKind MapType = OMPC_MAP_unknown;
|
||||
OpenMPMapClauseKind MapTypeModifier = OMPC_MAP_unknown;
|
||||
bool MapTypeIsImplicit = false;
|
||||
bool MapTypeModifierSpecified = false;
|
||||
SourceLocation DepLinMapLoc;
|
||||
SmallVector<Expr *, 4> Vars;
|
||||
OpenMPVarListDataTy Data;
|
||||
|
||||
// Parse '('.
|
||||
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
|
||||
if (T.expectAndConsume(diag::err_expected_lparen_after,
|
||||
getOpenMPClauseName(Kind)))
|
||||
if (ParseOpenMPVarList(DKind, Kind, Vars, Data))
|
||||
return nullptr;
|
||||
|
||||
bool NeedRParenForLinear = false;
|
||||
BalancedDelimiterTracker LinearT(*this, tok::l_paren,
|
||||
tok::annot_pragma_openmp_end);
|
||||
// Handle reduction-identifier for reduction clause.
|
||||
if (Kind == OMPC_reduction) {
|
||||
ColonProtectionRAIIObject ColonRAII(*this);
|
||||
if (getLangOpts().CPlusPlus)
|
||||
ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec,
|
||||
/*ObjectType=*/nullptr,
|
||||
/*EnteringContext=*/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";
|
||||
}
|
||||
} else if (Kind == OMPC_depend) {
|
||||
// Handle dependency type for depend clause.
|
||||
ColonProtectionRAIIObject ColonRAII(*this);
|
||||
DepKind = static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType(
|
||||
Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""));
|
||||
DepLinMapLoc = Tok.getLocation();
|
||||
|
||||
if (DepKind == OMPC_DEPEND_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 && DepKind == OMPC_DEPEND_source) {
|
||||
// Parse ')'.
|
||||
T.consumeClose();
|
||||
return Actions.ActOnOpenMPVarListClause(
|
||||
Kind, llvm::None, /*TailExpr=*/nullptr, Loc, LOpen,
|
||||
/*ColonLoc=*/SourceLocation(), Tok.getLocation(),
|
||||
ReductionIdScopeSpec, DeclarationNameInfo(), DepKind,
|
||||
LinearModifier, MapTypeModifier, MapType, MapTypeIsImplicit,
|
||||
DepLinMapLoc);
|
||||
}
|
||||
}
|
||||
if (Tok.is(tok::colon)) {
|
||||
ColonLoc = ConsumeToken();
|
||||
} else {
|
||||
Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren
|
||||
: diag::warn_pragma_expected_colon)
|
||||
<< "dependency type";
|
||||
}
|
||||
} else if (Kind == OMPC_linear) {
|
||||
// Try to parse modifier if any.
|
||||
if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) {
|
||||
LinearModifier = static_cast<OpenMPLinearClauseKind>(
|
||||
getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)));
|
||||
DepLinMapLoc = ConsumeToken();
|
||||
LinearT.consumeOpen();
|
||||
NeedRParenForLinear = true;
|
||||
}
|
||||
} else if (Kind == OMPC_map) {
|
||||
// Handle map type for map clause.
|
||||
ColonProtectionRAIIObject ColonRAII(*this);
|
||||
|
||||
/// The map clause modifier token can be either a identifier or the C++
|
||||
/// delete keyword.
|
||||
auto IsMapClauseModifierToken = [](const Token &Tok) {
|
||||
return Tok.isOneOf(tok::identifier, tok::kw_delete);
|
||||
};
|
||||
|
||||
// The first identifier may be a list item, a map-type or a
|
||||
// map-type-modifier. The map modifier can also be delete which has the same
|
||||
// spelling of the C++ delete keyword.
|
||||
MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType(
|
||||
Kind, IsMapClauseModifierToken(Tok) ? PP.getSpelling(Tok) : ""));
|
||||
DepLinMapLoc = Tok.getLocation();
|
||||
bool ColonExpected = false;
|
||||
|
||||
if (IsMapClauseModifierToken(Tok)) {
|
||||
if (PP.LookAhead(0).is(tok::colon)) {
|
||||
MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType(
|
||||
Kind, IsMapClauseModifierToken(Tok) ? PP.getSpelling(Tok) : ""));
|
||||
if (MapType == OMPC_MAP_unknown) {
|
||||
Diag(Tok, diag::err_omp_unknown_map_type);
|
||||
} else if (MapType == OMPC_MAP_always) {
|
||||
Diag(Tok, diag::err_omp_map_type_missing);
|
||||
}
|
||||
ConsumeToken();
|
||||
} else if (PP.LookAhead(0).is(tok::comma)) {
|
||||
if (IsMapClauseModifierToken(PP.LookAhead(1)) &&
|
||||
PP.LookAhead(2).is(tok::colon)) {
|
||||
MapTypeModifier =
|
||||
static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType(
|
||||
Kind,
|
||||
IsMapClauseModifierToken(Tok) ? PP.getSpelling(Tok) : ""));
|
||||
if (MapTypeModifier != OMPC_MAP_always) {
|
||||
Diag(Tok, diag::err_omp_unknown_map_type_modifier);
|
||||
MapTypeModifier = OMPC_MAP_unknown;
|
||||
} else {
|
||||
MapTypeModifierSpecified = true;
|
||||
}
|
||||
|
||||
ConsumeToken();
|
||||
ConsumeToken();
|
||||
|
||||
MapType = static_cast<OpenMPMapClauseKind>(getOpenMPSimpleClauseType(
|
||||
Kind, IsMapClauseModifierToken(Tok) ? PP.getSpelling(Tok) : ""));
|
||||
if (MapType == OMPC_MAP_unknown || MapType == OMPC_MAP_always) {
|
||||
Diag(Tok, diag::err_omp_unknown_map_type);
|
||||
}
|
||||
ConsumeToken();
|
||||
} else {
|
||||
MapType = OMPC_MAP_tofrom;
|
||||
MapTypeIsImplicit = true;
|
||||
}
|
||||
} else {
|
||||
MapType = OMPC_MAP_tofrom;
|
||||
MapTypeIsImplicit = true;
|
||||
}
|
||||
} else {
|
||||
MapType = OMPC_MAP_tofrom;
|
||||
MapTypeIsImplicit = true;
|
||||
}
|
||||
|
||||
if (Tok.is(tok::colon)) {
|
||||
ColonLoc = ConsumeToken();
|
||||
} else if (ColonExpected) {
|
||||
Diag(Tok, diag::warn_pragma_expected_colon) << "map type";
|
||||
}
|
||||
}
|
||||
|
||||
SmallVector<Expr *, 5> Vars;
|
||||
bool IsComma =
|
||||
((Kind != OMPC_reduction) && (Kind != OMPC_depend) &&
|
||||
(Kind != OMPC_map)) ||
|
||||
((Kind == OMPC_reduction) && !InvalidReductionId) ||
|
||||
((Kind == OMPC_map) && (MapType != OMPC_MAP_unknown) &&
|
||||
(!MapTypeModifierSpecified || MapTypeModifier == OMPC_MAP_always)) ||
|
||||
((Kind == OMPC_depend) && DepKind != OMPC_DEPEND_unknown);
|
||||
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))) {
|
||||
ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
|
||||
// Parse variable
|
||||
ExprResult VarExpr =
|
||||
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
|
||||
if (VarExpr.isUsable()) {
|
||||
Vars.push_back(VarExpr.get());
|
||||
} else {
|
||||
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
||||
StopBeforeMatch);
|
||||
}
|
||||
// Skip ',' if any
|
||||
IsComma = Tok.is(tok::comma);
|
||||
if (IsComma)
|
||||
ConsumeToken();
|
||||
else if (Tok.isNot(tok::r_paren) &&
|
||||
Tok.isNot(tok::annot_pragma_openmp_end) &&
|
||||
(!MayHaveTail || Tok.isNot(tok::colon)))
|
||||
Diag(Tok, diag::err_omp_expected_punc)
|
||||
<< ((Kind == OMPC_flush) ? getOpenMPDirectiveName(OMPD_flush)
|
||||
: getOpenMPClauseName(Kind))
|
||||
<< (Kind == OMPC_flush);
|
||||
}
|
||||
|
||||
// Parse ')' for linear clause with modifier.
|
||||
if (NeedRParenForLinear)
|
||||
LinearT.consumeClose();
|
||||
|
||||
// Parse ':' linear-step (or ':' alignment).
|
||||
Expr *TailExpr = nullptr;
|
||||
const bool MustHaveTail = MayHaveTail && Tok.is(tok::colon);
|
||||
if (MustHaveTail) {
|
||||
ColonLoc = Tok.getLocation();
|
||||
SourceLocation ELoc = ConsumeToken();
|
||||
ExprResult Tail = ParseAssignmentExpression();
|
||||
Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc);
|
||||
if (Tail.isUsable())
|
||||
TailExpr = Tail.get();
|
||||
else
|
||||
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
|
||||
StopBeforeMatch);
|
||||
}
|
||||
|
||||
// Parse ')'.
|
||||
T.consumeClose();
|
||||
if ((Kind == OMPC_depend && DepKind != OMPC_DEPEND_unknown && Vars.empty()) ||
|
||||
(Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) ||
|
||||
(MustHaveTail && !TailExpr) || InvalidReductionId) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Actions.ActOnOpenMPVarListClause(
|
||||
Kind, Vars, TailExpr, Loc, LOpen, ColonLoc, Tok.getLocation(),
|
||||
ReductionIdScopeSpec,
|
||||
ReductionId.isValid() ? Actions.GetNameFromUnqualifiedId(ReductionId)
|
||||
: DeclarationNameInfo(),
|
||||
DepKind, LinearModifier, MapTypeModifier, MapType, MapTypeIsImplicit,
|
||||
DepLinMapLoc);
|
||||
Kind, Vars, Data.TailExpr, Loc, LOpen, Data.ColonLoc, Tok.getLocation(),
|
||||
Data.ReductionIdScopeSpec, Data.ReductionId, Data.DepKind, Data.LinKind,
|
||||
Data.MapTypeModifier, Data.MapType, Data.IsMapTypeImplicit,
|
||||
Data.DepLinMapLoc);
|
||||
}
|
||||
|
||||
|
|
|
@ -3190,10 +3190,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
|
|||
return Res;
|
||||
}
|
||||
|
||||
Sema::DeclGroupPtrTy
|
||||
Sema::ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
|
||||
OMPDeclareSimdDeclAttr::BranchStateTy BS,
|
||||
Expr *Simdlen, SourceRange SR) {
|
||||
Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
|
||||
DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, Expr *Simdlen,
|
||||
ArrayRef<Expr *> Uniforms, SourceRange SR) {
|
||||
if (!DG || DG.get().isNull())
|
||||
return DeclGroupPtrTy();
|
||||
|
||||
|
@ -3205,9 +3204,9 @@ Sema::ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
|
|||
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl))
|
||||
ADecl = FTD->getTemplatedDecl();
|
||||
|
||||
if (!isa<FunctionDecl>(ADecl)) {
|
||||
Diag(ADecl->getLocation(), diag::err_omp_function_expected)
|
||||
<< ADecl->getDeclContext()->isFileContext();
|
||||
auto *FD = dyn_cast<FunctionDecl>(ADecl);
|
||||
if (!FD) {
|
||||
Diag(ADecl->getLocation(), diag::err_omp_function_expected);
|
||||
return DeclGroupPtrTy();
|
||||
}
|
||||
|
||||
|
@ -3215,13 +3214,30 @@ Sema::ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
|
|||
// The parameter of the simdlen clause must be a constant positive integer
|
||||
// expression.
|
||||
ExprResult SL;
|
||||
if (Simdlen) {
|
||||
if (Simdlen)
|
||||
SL = VerifyPositiveIntegerConstantInClause(Simdlen, OMPC_simdlen);
|
||||
if (SL.isInvalid())
|
||||
return DG;
|
||||
// OpenMP [2.8.2, declare simd construct, Description]
|
||||
// The special this pointer can be used as if was one of the arguments to the
|
||||
// function in any of the linear, aligned, or uniform clauses.
|
||||
// The uniform clause declares one or more arguments to have an invariant
|
||||
// value for all concurrent invocations of the function in the execution of a
|
||||
// single SIMD loop.
|
||||
for (auto *E : Uniforms) {
|
||||
E = E->IgnoreParenImpCasts();
|
||||
if (auto *DRE = dyn_cast<DeclRefExpr>(E))
|
||||
if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
|
||||
if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
|
||||
FD->getParamDecl(PVD->getFunctionScopeIndex())
|
||||
->getCanonicalDecl() == PVD->getCanonicalDecl())
|
||||
continue;
|
||||
if (isa<CXXThisExpr>(E))
|
||||
continue;
|
||||
Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
|
||||
<< FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0);
|
||||
}
|
||||
auto *NewAttr =
|
||||
OMPDeclareSimdDeclAttr::CreateImplicit(Context, BS, SL.get(), SR);
|
||||
auto *NewAttr = OMPDeclareSimdDeclAttr::CreateImplicit(
|
||||
Context, BS, SL.get(), const_cast<Expr **>(Uniforms.data()),
|
||||
Uniforms.size(), SR);
|
||||
ADecl->addAttr(NewAttr);
|
||||
return ConvertDeclToDeclGroup(ADecl);
|
||||
}
|
||||
|
@ -6386,6 +6402,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
|
|||
case OMPC_dist_schedule:
|
||||
case OMPC_defaultmap:
|
||||
case OMPC_unknown:
|
||||
case OMPC_uniform:
|
||||
llvm_unreachable("Clause is not allowed.");
|
||||
}
|
||||
return Res;
|
||||
|
@ -6671,6 +6688,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
|
|||
case OMPC_dist_schedule:
|
||||
case OMPC_defaultmap:
|
||||
case OMPC_unknown:
|
||||
case OMPC_uniform:
|
||||
llvm_unreachable("Clause is not allowed.");
|
||||
}
|
||||
return Res;
|
||||
|
@ -6821,6 +6839,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
|
|||
case OMPC_num_tasks:
|
||||
case OMPC_hint:
|
||||
case OMPC_unknown:
|
||||
case OMPC_uniform:
|
||||
llvm_unreachable("Clause is not allowed.");
|
||||
}
|
||||
return Res;
|
||||
|
@ -7004,6 +7023,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
|
|||
case OMPC_dist_schedule:
|
||||
case OMPC_defaultmap:
|
||||
case OMPC_unknown:
|
||||
case OMPC_uniform:
|
||||
llvm_unreachable("Clause is not allowed.");
|
||||
}
|
||||
return Res;
|
||||
|
@ -7149,6 +7169,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
|
|||
case OMPC_dist_schedule:
|
||||
case OMPC_defaultmap:
|
||||
case OMPC_unknown:
|
||||
case OMPC_uniform:
|
||||
llvm_unreachable("Clause is not allowed.");
|
||||
}
|
||||
return Res;
|
||||
|
|
|
@ -240,15 +240,42 @@ static void instantiateOMPDeclareSimdDeclAttr(
|
|||
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
const OMPDeclareSimdDeclAttr &Attr, Decl *New) {
|
||||
ExprResult Simdlen;
|
||||
if (auto *E = Attr.getSimdlen()) {
|
||||
if (auto *E = Attr.getSimdlen())
|
||||
Simdlen = S.SubstExpr(E, TemplateArgs);
|
||||
if (Simdlen.isInvalid())
|
||||
return;
|
||||
// Allow 'this' in clauses with varlists.
|
||||
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(New))
|
||||
New = FTD->getTemplatedDecl();
|
||||
auto *FD = cast<FunctionDecl>(New);
|
||||
auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(FD->getDeclContext());
|
||||
SmallVector<Expr *, 4> Uniforms;
|
||||
|
||||
auto &&Subst = [&](Expr *E) -> ExprResult {
|
||||
if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
|
||||
if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
|
||||
Sema::ContextRAII SavedContext(S, FD);
|
||||
LocalInstantiationScope Local(S);
|
||||
if (FD->getNumParams() > PVD->getFunctionScopeIndex())
|
||||
Local.InstantiatedLocal(
|
||||
PVD, FD->getParamDecl(PVD->getFunctionScopeIndex()));
|
||||
return S.SubstExpr(E, TemplateArgs);
|
||||
}
|
||||
Sema::CXXThisScopeRAII ThisScope(S, ThisContext, /*TypeQuals=*/0,
|
||||
FD->isCXXInstanceMember());
|
||||
return S.SubstExpr(E, TemplateArgs);
|
||||
};
|
||||
|
||||
if (Attr.uniforms_size() > 0) {
|
||||
for(auto *E : Attr.uniforms()) {
|
||||
ExprResult Inst = Subst(E);
|
||||
if (Inst.isInvalid())
|
||||
continue;
|
||||
Uniforms.push_back(Inst.get());
|
||||
}
|
||||
}
|
||||
|
||||
(void)S.ActOnOpenMPDeclareSimdDirective(S.ConvertDeclToDeclGroup(New),
|
||||
Attr.getBranchState(), Simdlen.get(),
|
||||
Attr.getRange());
|
||||
Uniforms, Attr.getRange());
|
||||
}
|
||||
|
||||
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
|
|
|
@ -8,12 +8,12 @@
|
|||
|
||||
#pragma omp declare simd
|
||||
#pragma omp declare simd simdlen(32)
|
||||
#pragma omp declare simd inbranch
|
||||
#pragma omp declare simd notinbranch simdlen(2)
|
||||
#pragma omp declare simd inbranch, uniform(d)
|
||||
#pragma omp declare simd notinbranch simdlen(2), uniform(s1, s2)
|
||||
void add_1(float *d, float *s1, float *s2) __attribute__((cold));
|
||||
|
||||
// CHECK: #pragma omp declare simd notinbranch simdlen(2)
|
||||
// CHECK-NEXT: #pragma omp declare simd inbranch
|
||||
// CHECK: #pragma omp declare simd notinbranch simdlen(2) uniform(s1, s2)
|
||||
// CHECK-NEXT: #pragma omp declare simd inbranch uniform(d)
|
||||
// CHECK-NEXT: #pragma omp declare simd simdlen(32)
|
||||
// CHECK-NEXT: #pragma omp declare simd
|
||||
// CHECK-NEXT: void add_1(float *d, float *s1, float *s2) __attribute__((cold))
|
||||
|
|
|
@ -48,11 +48,11 @@ void h(int *hp, int *hp2, int *hq, int *lin)
|
|||
}
|
||||
|
||||
class VV {
|
||||
// CHECK: #pragma omp declare simd
|
||||
// CHECK: #pragma omp declare simd uniform(this, a)
|
||||
// CHECK-NEXT: int add(int a, int b) __attribute__((cold)) {
|
||||
// CHECK-NEXT: return a + b;
|
||||
// CHECK-NEXT: }
|
||||
#pragma omp declare simd
|
||||
#pragma omp declare simd uniform(this, a)
|
||||
int add(int a, int b) __attribute__((cold)) { return a + b; }
|
||||
|
||||
// CHECK: #pragma omp declare simd
|
||||
|
@ -109,10 +109,10 @@ public:
|
|||
// CHECK-NEXT: }
|
||||
|
||||
#pragma omp declare simd
|
||||
#pragma omp declare simd
|
||||
#pragma omp declare simd uniform(this, b)
|
||||
int tadd(int b) { return x[b] + b; }
|
||||
|
||||
// CHECK: #pragma omp declare simd
|
||||
// CHECK: #pragma omp declare simd uniform(this, b)
|
||||
// CHECK-NEXT: #pragma omp declare simd
|
||||
// CHECK-NEXT: int tadd(int b) {
|
||||
// CHECK-NEXT: return this->x[b] + b;
|
||||
|
|
|
@ -75,8 +75,10 @@ void h(int *hp, int *hp2, int *hq, int *lin) {
|
|||
#pragma omp declare simd simdlen() simdlen)
|
||||
void foo();
|
||||
|
||||
// expected-error@+3 2 {{expected reference to one of the parameters of function 'foo'}}
|
||||
// expected-error@+2 {{invalid use of 'this' outside of a non-static member function}}
|
||||
// expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
|
||||
#pragma omp declare simd simdlen(N)
|
||||
#pragma omp declare simd simdlen(N) uniform(this, var)
|
||||
template<int N>
|
||||
void foo() {}
|
||||
|
||||
|
@ -85,12 +87,34 @@ void test() {
|
|||
foo<-3>();
|
||||
}
|
||||
|
||||
// expected-error@+1 {{expected '(' after 'uniform'}}
|
||||
#pragma omp declare simd uniform
|
||||
// expected-note@+3 {{to match this '('}}
|
||||
// expected-error@+2 {{expected ')'}}
|
||||
// expected-error@+1 {{expected expression}}
|
||||
#pragma omp declare simd uniform(
|
||||
// expected-error@+1 {{expected expression}}
|
||||
#pragma omp declare simd uniform()
|
||||
// expected-note@+3 {{to match this '('}}
|
||||
// expected-error@+2 {{expected ')'}}
|
||||
// expected-error@+1 {{invalid use of 'this' outside of a non-static member function}}
|
||||
#pragma omp declare simd uniform(this
|
||||
// expected-note@+3 {{to match this '('}}
|
||||
// expected-error@+2 {{expected ')'}}
|
||||
// expected-error@+1 {{invalid use of 'this' outside of a non-static member function}}
|
||||
#pragma omp declare simd uniform(this,a
|
||||
// expected-error@+1 {{expected expression}}
|
||||
#pragma omp declare simd uniform(,a)
|
||||
void bar(int a);
|
||||
|
||||
template <class T>
|
||||
struct St {
|
||||
// expected-error@+2 {{function declaration is expected after 'declare simd' directive}}
|
||||
#pragma init_seg(compiler)
|
||||
#pragma omp declare simd
|
||||
#pragma init_seg(compiler)
|
||||
// expected-error@+1 {{use of undeclared identifier 't'}}
|
||||
#pragma omp declare simd uniform(this, t)
|
||||
void h(T *hp) {
|
||||
// expected-error@+1 {{unexpected OpenMP directive '#pragma omp declare simd'}}
|
||||
#pragma omp declare simd
|
||||
|
|
Loading…
Reference in New Issue