[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:
Alexey Bataev 2016-04-12 05:28:34 +00:00
parent 94f58e79ae
commit e48a5fc56d
15 changed files with 376 additions and 255 deletions

View File

@ -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;
}

View File

@ -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 << ") ";
}
}
}];
}

View File

@ -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 {

View File

@ -35,6 +35,7 @@ enum OpenMPClauseKind {
OMPC_##Name,
#include "clang/Basic/OpenMPKinds.def"
OMPC_threadprivate,
OMPC_uniform,
OMPC_unknown
};

View File

@ -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,

View File

@ -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,

View File

@ -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;
}

View File

@ -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");

View File

@ -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'.");
}
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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,

View File

@ -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))

View File

@ -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;

View File

@ -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