forked from OSchip/llvm-project
[OPENMP 4.0] Parsing/sema analysis for 'simdlen' clause in 'declare simd'
construct. OpenMP 4.0 defines '#pragma omp declare simd' construct that may have associated 'simdlen' clause with constant positive expression as an argument: simdlen(<const_expr>) Patch adds parsin and semantic analysis for simdlen clause. llvm-svn: 265668
This commit is contained in:
parent
a1feff7024
commit
2af33e3d3f
|
@ -2265,13 +2265,22 @@ def OMPDeclareSimdDecl : Attr {
|
||||||
let SemaHandler = 0;
|
let SemaHandler = 0;
|
||||||
let HasCustomParsing = 1;
|
let HasCustomParsing = 1;
|
||||||
let Documentation = [OMPDeclareSimdDocs];
|
let Documentation = [OMPDeclareSimdDocs];
|
||||||
let Args = [EnumArgument<"BranchState", "BranchStateTy",
|
let Args = [
|
||||||
["", "inbranch", "notinbranch"],
|
EnumArgument<"BranchState", "BranchStateTy",
|
||||||
["BS_Undefined", "BS_Inbranch", "BS_Notinbranch"]>];
|
[ "", "inbranch", "notinbranch" ],
|
||||||
|
[ "BS_Undefined", "BS_Inbranch", "BS_Notinbranch" ]>,
|
||||||
|
ExprArgument<"Simdlen">
|
||||||
|
];
|
||||||
let AdditionalMembers = [{
|
let AdditionalMembers = [{
|
||||||
void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy)
|
void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy)
|
||||||
const {
|
const {
|
||||||
OS << ' ' << ConvertBranchStateTyToStr(getBranchState());
|
if (getBranchState() != BS_Undefined)
|
||||||
|
OS << ConvertBranchStateTyToStr(getBranchState()) << " ";
|
||||||
|
if (auto *E = getSimdlen()) {
|
||||||
|
OS << "simdlen(";
|
||||||
|
E->printPretty(OS, nullptr, Policy);
|
||||||
|
OS << ") ";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
|
@ -2456,6 +2456,10 @@ private:
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
// OpenMP: Directives and clauses.
|
// OpenMP: Directives and clauses.
|
||||||
|
/// Parse clauses for '#pragma omp declare simd'.
|
||||||
|
DeclGroupPtrTy ParseOMPDeclareSimdClauses(DeclGroupPtrTy Ptr,
|
||||||
|
CachedTokens &Toks,
|
||||||
|
SourceLocation Loc);
|
||||||
/// \brief Parses declarative OpenMP directives.
|
/// \brief Parses declarative OpenMP directives.
|
||||||
DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl(
|
DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl(
|
||||||
AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
|
AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
|
||||||
|
@ -2520,6 +2524,10 @@ private:
|
||||||
OpenMPClauseKind Kind);
|
OpenMPClauseKind Kind);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// Parses simple expression in parens for single-expression clauses of OpenMP
|
||||||
|
/// constructs.
|
||||||
|
/// \param LLoc Returned location of left paren.
|
||||||
|
ExprResult ParseOpenMPParensExpr(StringRef ClauseName, SourceLocation &RLoc);
|
||||||
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
bool AllowDestructorName,
|
bool AllowDestructorName,
|
||||||
bool AllowConstructorName,
|
bool AllowConstructorName,
|
||||||
|
|
|
@ -8107,7 +8107,7 @@ public:
|
||||||
DeclGroupPtrTy
|
DeclGroupPtrTy
|
||||||
ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
|
ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
|
||||||
OMPDeclareSimdDeclAttr::BranchStateTy BS,
|
OMPDeclareSimdDeclAttr::BranchStateTy BS,
|
||||||
SourceRange SR);
|
Expr *Simdlen, SourceRange SR);
|
||||||
|
|
||||||
OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
|
OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
|
||||||
Expr *Expr,
|
Expr *Expr,
|
||||||
|
|
|
@ -332,32 +332,134 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
|
||||||
/// Parses clauses for 'declare simd' directive.
|
/// Parses clauses for 'declare simd' directive.
|
||||||
/// clause:
|
/// clause:
|
||||||
/// 'inbranch' | 'notinbranch'
|
/// 'inbranch' | 'notinbranch'
|
||||||
static void parseDeclareSimdClauses(Parser &P,
|
/// 'simdlen' '('<expr> ')'
|
||||||
OMPDeclareSimdDeclAttr::BranchStateTy &BS) {
|
static bool parseDeclareSimdClauses(Parser &P,
|
||||||
|
OMPDeclareSimdDeclAttr::BranchStateTy &BS,
|
||||||
|
ExprResult &SimdLen) {
|
||||||
SourceRange BSRange;
|
SourceRange BSRange;
|
||||||
const Token &Tok = P.getCurToken();
|
const Token &Tok = P.getCurToken();
|
||||||
|
bool IsError = false;
|
||||||
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
|
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
|
||||||
if (Tok.isNot(tok::identifier))
|
if (Tok.isNot(tok::identifier))
|
||||||
break;
|
break;
|
||||||
OMPDeclareSimdDeclAttr::BranchStateTy Out;
|
OMPDeclareSimdDeclAttr::BranchStateTy Out;
|
||||||
StringRef TokName = Tok.getIdentifierInfo()->getName();
|
IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||||
|
StringRef ClauseName = II->getName();
|
||||||
// Parse 'inranch|notinbranch' clauses.
|
// Parse 'inranch|notinbranch' clauses.
|
||||||
if (OMPDeclareSimdDeclAttr::ConvertStrToBranchStateTy(TokName, Out)) {
|
if (OMPDeclareSimdDeclAttr::ConvertStrToBranchStateTy(ClauseName, Out)) {
|
||||||
if (BS != OMPDeclareSimdDeclAttr::BS_Undefined && BS != Out) {
|
if (BS != OMPDeclareSimdDeclAttr::BS_Undefined && BS != Out) {
|
||||||
P.Diag(Tok, diag::err_omp_declare_simd_inbranch_notinbranch)
|
P.Diag(Tok, diag::err_omp_declare_simd_inbranch_notinbranch)
|
||||||
<< TokName << OMPDeclareSimdDeclAttr::ConvertBranchStateTyToStr(BS)
|
<< ClauseName
|
||||||
<< BSRange;
|
<< OMPDeclareSimdDeclAttr::ConvertBranchStateTyToStr(BS) << BSRange;
|
||||||
|
IsError = true;
|
||||||
}
|
}
|
||||||
BS = Out;
|
BS = Out;
|
||||||
BSRange = SourceRange(Tok.getLocation(), Tok.getEndLoc());
|
BSRange = SourceRange(Tok.getLocation(), Tok.getEndLoc());
|
||||||
|
P.ConsumeToken();
|
||||||
|
} else if (ClauseName.equals("simdlen")) {
|
||||||
|
if (SimdLen.isUsable()) {
|
||||||
|
P.Diag(Tok, diag::err_omp_more_one_clause)
|
||||||
|
<< getOpenMPDirectiveName(OMPD_declare_simd) << ClauseName << 0;
|
||||||
|
IsError = true;
|
||||||
|
}
|
||||||
|
P.ConsumeToken();
|
||||||
|
SourceLocation RLoc;
|
||||||
|
SimdLen = P.ParseOpenMPParensExpr(ClauseName, RLoc);
|
||||||
|
if (SimdLen.isInvalid())
|
||||||
|
IsError = true;
|
||||||
} else
|
} else
|
||||||
// TODO: add parsing of other clauses.
|
// TODO: add parsing of other clauses.
|
||||||
break;
|
break;
|
||||||
P.ConsumeToken();
|
|
||||||
// Skip ',' if any.
|
// Skip ',' if any.
|
||||||
if (Tok.is(tok::comma))
|
if (Tok.is(tok::comma))
|
||||||
P.ConsumeToken();
|
P.ConsumeToken();
|
||||||
}
|
}
|
||||||
|
return IsError;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/// RAII that recreates function context for correct parsing of clauses of
|
||||||
|
/// 'declare simd' construct.
|
||||||
|
/// OpenMP, 2.8.2 declare simd Construct
|
||||||
|
/// The expressions appearing in the clauses of this directive are evaluated in
|
||||||
|
/// the scope of the arguments of the function declaration or definition.
|
||||||
|
class FNContextRAII final {
|
||||||
|
Parser &P;
|
||||||
|
Sema::CXXThisScopeRAII *ThisScope;
|
||||||
|
Parser::ParseScope *TempScope;
|
||||||
|
Parser::ParseScope *FnScope;
|
||||||
|
bool HasTemplateScope = false;
|
||||||
|
bool HasFunScope = false;
|
||||||
|
FNContextRAII() = delete;
|
||||||
|
FNContextRAII(const FNContextRAII &) = delete;
|
||||||
|
FNContextRAII &operator=(const FNContextRAII &) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr) : P(P) {
|
||||||
|
Decl *D = *Ptr.get().begin();
|
||||||
|
NamedDecl *ND = dyn_cast<NamedDecl>(D);
|
||||||
|
RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());
|
||||||
|
Sema &Actions = P.getActions();
|
||||||
|
|
||||||
|
// Allow 'this' within late-parsed attributes.
|
||||||
|
ThisScope = new Sema::CXXThisScopeRAII(Actions, RD, /*TypeQuals=*/0,
|
||||||
|
ND && ND->isCXXInstanceMember());
|
||||||
|
|
||||||
|
// If the Decl is templatized, add template parameters to scope.
|
||||||
|
HasTemplateScope = D->isTemplateDecl();
|
||||||
|
TempScope =
|
||||||
|
new Parser::ParseScope(&P, Scope::TemplateParamScope, HasTemplateScope);
|
||||||
|
if (HasTemplateScope)
|
||||||
|
Actions.ActOnReenterTemplateScope(Actions.getCurScope(), D);
|
||||||
|
|
||||||
|
// If the Decl is on a function, add function parameters to the scope.
|
||||||
|
HasFunScope = D->isFunctionOrFunctionTemplate();
|
||||||
|
FnScope = new Parser::ParseScope(&P, Scope::FnScope | Scope::DeclScope,
|
||||||
|
HasFunScope);
|
||||||
|
if (HasFunScope)
|
||||||
|
Actions.ActOnReenterFunctionContext(Actions.getCurScope(), D);
|
||||||
|
}
|
||||||
|
~FNContextRAII() {
|
||||||
|
if (HasFunScope) {
|
||||||
|
P.getActions().ActOnExitFunctionContext();
|
||||||
|
FnScope->Exit(); // Pop scope, and remove Decls from IdResolver
|
||||||
|
}
|
||||||
|
if (HasTemplateScope)
|
||||||
|
TempScope->Exit();
|
||||||
|
delete FnScope;
|
||||||
|
delete TempScope;
|
||||||
|
delete ThisScope;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
/// Parse clauses for '#pragma omp declare simd'.
|
||||||
|
Parser::DeclGroupPtrTy
|
||||||
|
Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
|
||||||
|
CachedTokens &Toks, SourceLocation Loc) {
|
||||||
|
PP.EnterToken(Tok);
|
||||||
|
PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true);
|
||||||
|
// Consume the previously pushed token.
|
||||||
|
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
|
||||||
|
|
||||||
|
FNContextRAII FnContext(*this, Ptr);
|
||||||
|
OMPDeclareSimdDeclAttr::BranchStateTy BS =
|
||||||
|
OMPDeclareSimdDeclAttr::BS_Undefined;
|
||||||
|
ExprResult Simdlen;
|
||||||
|
bool IsError = parseDeclareSimdClauses(*this, BS, Simdlen);
|
||||||
|
// Need to check for extra tokens.
|
||||||
|
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
|
||||||
|
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
|
||||||
|
<< getOpenMPDirectiveName(OMPD_declare_simd);
|
||||||
|
while (Tok.isNot(tok::annot_pragma_openmp_end))
|
||||||
|
ConsumeAnyToken();
|
||||||
|
}
|
||||||
|
// Skip the last annot_pragma_openmp_end.
|
||||||
|
SourceLocation EndLoc = ConsumeToken();
|
||||||
|
if (!IsError)
|
||||||
|
return Actions.ActOnOpenMPDeclareSimdDirective(Ptr, BS, Simdlen.get(),
|
||||||
|
SourceRange(Loc, EndLoc));
|
||||||
|
return Ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Parsing of declarative OpenMP directives.
|
/// \brief Parsing of declarative OpenMP directives.
|
||||||
|
@ -382,7 +484,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
|
||||||
ParenBraceBracketBalancer BalancerRAIIObj(*this);
|
ParenBraceBracketBalancer BalancerRAIIObj(*this);
|
||||||
|
|
||||||
SourceLocation Loc = ConsumeToken();
|
SourceLocation Loc = ConsumeToken();
|
||||||
SmallVector<Expr *, 5> Identifiers;
|
SmallVector<Expr *, 4> Identifiers;
|
||||||
auto DKind = ParseOpenMPDirectiveKind(*this);
|
auto DKind = ParseOpenMPDirectiveKind(*this);
|
||||||
|
|
||||||
switch (DKind) {
|
switch (DKind) {
|
||||||
|
@ -422,21 +524,10 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
|
||||||
// { #pragma omp declare simd }
|
// { #pragma omp declare simd }
|
||||||
// <function-declaration-or-definition>
|
// <function-declaration-or-definition>
|
||||||
//
|
//
|
||||||
|
|
||||||
ConsumeToken();
|
ConsumeToken();
|
||||||
OMPDeclareSimdDeclAttr::BranchStateTy BS =
|
CachedTokens Toks;
|
||||||
OMPDeclareSimdDeclAttr::BS_Undefined;
|
ConsumeAndStoreUntil(tok::annot_pragma_openmp_end, Toks,
|
||||||
parseDeclareSimdClauses(*this, BS);
|
/*StopAtSemi=*/false, /*ConsumeFinalToken=*/true);
|
||||||
|
|
||||||
// Need to check for extra tokens.
|
|
||||||
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
|
|
||||||
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
|
|
||||||
<< getOpenMPDirectiveName(OMPD_declare_simd);
|
|
||||||
while (Tok.isNot(tok::annot_pragma_openmp_end))
|
|
||||||
ConsumeAnyToken();
|
|
||||||
}
|
|
||||||
// Skip the last annot_pragma_openmp_end.
|
|
||||||
SourceLocation EndLoc = ConsumeToken();
|
|
||||||
|
|
||||||
DeclGroupPtrTy Ptr;
|
DeclGroupPtrTy Ptr;
|
||||||
if (Tok.is(tok::annot_pragma_openmp))
|
if (Tok.is(tok::annot_pragma_openmp))
|
||||||
|
@ -458,9 +549,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
|
||||||
Diag(Loc, diag::err_omp_decl_in_declare_simd);
|
Diag(Loc, diag::err_omp_decl_in_declare_simd);
|
||||||
return DeclGroupPtrTy();
|
return DeclGroupPtrTy();
|
||||||
}
|
}
|
||||||
|
return ParseOMPDeclareSimdClauses(Ptr, Toks, Loc);
|
||||||
return Actions.ActOnOpenMPDeclareSimdDirective(Ptr, BS,
|
|
||||||
SourceRange(Loc, EndLoc));
|
|
||||||
}
|
}
|
||||||
case OMPD_declare_target: {
|
case OMPD_declare_target: {
|
||||||
SourceLocation DTLoc = ConsumeAnyToken();
|
SourceLocation DTLoc = ConsumeAnyToken();
|
||||||
|
@ -1000,6 +1089,28 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
|
||||||
return ErrorFound ? nullptr : Clause;
|
return ErrorFound ? nullptr : Clause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses simple expression in parens for single-expression clauses of OpenMP
|
||||||
|
/// constructs.
|
||||||
|
/// \param RLoc Returned location of right paren.
|
||||||
|
ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName,
|
||||||
|
SourceLocation &RLoc) {
|
||||||
|
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
|
||||||
|
if (T.expectAndConsume(diag::err_expected_lparen_after, ClauseName.data()))
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
|
SourceLocation ELoc = Tok.getLocation();
|
||||||
|
ExprResult LHS(ParseCastExpression(
|
||||||
|
/*isUnaryExpression=*/false, /*isAddressOfOperand=*/false, NotTypeCast));
|
||||||
|
ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
|
||||||
|
Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc);
|
||||||
|
|
||||||
|
// Parse ')'.
|
||||||
|
T.consumeClose();
|
||||||
|
|
||||||
|
RLoc = T.getCloseLocation();
|
||||||
|
return Val;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Parsing of OpenMP clauses with single expressions like 'final',
|
/// \brief Parsing of OpenMP clauses with single expressions like 'final',
|
||||||
/// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams',
|
/// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams',
|
||||||
/// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks' or 'hint'.
|
/// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks' or 'hint'.
|
||||||
|
@ -1033,25 +1144,15 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
|
||||||
///
|
///
|
||||||
OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) {
|
OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) {
|
||||||
SourceLocation Loc = ConsumeToken();
|
SourceLocation Loc = ConsumeToken();
|
||||||
|
SourceLocation LLoc = Tok.getLocation();
|
||||||
|
SourceLocation RLoc;
|
||||||
|
|
||||||
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
|
ExprResult Val = ParseOpenMPParensExpr(getOpenMPClauseName(Kind), RLoc);
|
||||||
if (T.expectAndConsume(diag::err_expected_lparen_after,
|
|
||||||
getOpenMPClauseName(Kind)))
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
SourceLocation ELoc = Tok.getLocation();
|
|
||||||
ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
|
|
||||||
ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
|
|
||||||
Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc);
|
|
||||||
|
|
||||||
// Parse ')'.
|
|
||||||
T.consumeClose();
|
|
||||||
|
|
||||||
if (Val.isInvalid())
|
if (Val.isInvalid())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return Actions.ActOnOpenMPSingleExprClause(
|
return Actions.ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc, LLoc, RLoc);
|
||||||
Kind, Val.get(), Loc, T.getOpenLocation(), T.getCloseLocation());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
|
/// \brief Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
|
||||||
|
|
|
@ -3193,7 +3193,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
|
||||||
Sema::DeclGroupPtrTy
|
Sema::DeclGroupPtrTy
|
||||||
Sema::ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
|
Sema::ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
|
||||||
OMPDeclareSimdDeclAttr::BranchStateTy BS,
|
OMPDeclareSimdDeclAttr::BranchStateTy BS,
|
||||||
SourceRange SR) {
|
Expr *Simdlen, SourceRange SR) {
|
||||||
if (!DG || DG.get().isNull())
|
if (!DG || DG.get().isNull())
|
||||||
return DeclGroupPtrTy();
|
return DeclGroupPtrTy();
|
||||||
|
|
||||||
|
@ -3211,7 +3211,17 @@ Sema::ActOnOpenMPDeclareSimdDirective(DeclGroupPtrTy DG,
|
||||||
return DeclGroupPtrTy();
|
return DeclGroupPtrTy();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *NewAttr = OMPDeclareSimdDeclAttr::CreateImplicit(Context, BS, SR);
|
// OpenMP [2.8.2, declare simd construct, Description]
|
||||||
|
// The parameter of the simdlen clause must be a constant positive integer
|
||||||
|
// expression.
|
||||||
|
ExprResult SL;
|
||||||
|
if (Simdlen) {
|
||||||
|
SL = VerifyPositiveIntegerConstantInClause(Simdlen, OMPC_simdlen);
|
||||||
|
if (SL.isInvalid())
|
||||||
|
return DG;
|
||||||
|
}
|
||||||
|
auto *NewAttr =
|
||||||
|
OMPDeclareSimdDeclAttr::CreateImplicit(Context, BS, SL.get(), SR);
|
||||||
ADecl->addAttr(NewAttr);
|
ADecl->addAttr(NewAttr);
|
||||||
return ConvertDeclToDeclGroup(ADecl);
|
return ConvertDeclToDeclGroup(ADecl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,6 +235,22 @@ instantiateDependentModeAttr(Sema &S,
|
||||||
Attr.getSpellingListIndex(), /*InInstantiation=*/true);
|
Attr.getSpellingListIndex(), /*InInstantiation=*/true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Instantiation of 'declare simd' attribute and its arguments.
|
||||||
|
static void instantiateOMPDeclareSimdDeclAttr(
|
||||||
|
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||||
|
const OMPDeclareSimdDeclAttr &Attr, Decl *New) {
|
||||||
|
ExprResult Simdlen;
|
||||||
|
if (auto *E = Attr.getSimdlen()) {
|
||||||
|
Simdlen = S.SubstExpr(E, TemplateArgs);
|
||||||
|
if (Simdlen.isInvalid())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)S.ActOnOpenMPDeclareSimdDirective(S.ConvertDeclToDeclGroup(New),
|
||||||
|
Attr.getBranchState(), Simdlen.get(),
|
||||||
|
Attr.getRange());
|
||||||
|
}
|
||||||
|
|
||||||
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
|
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||||
const Decl *Tmpl, Decl *New,
|
const Decl *Tmpl, Decl *New,
|
||||||
LateInstantiatedAttrVec *LateAttrs,
|
LateInstantiatedAttrVec *LateAttrs,
|
||||||
|
@ -278,6 +294,11 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (const auto *OMPAttr = dyn_cast<OMPDeclareSimdDeclAttr>(TmplAttr)) {
|
||||||
|
instantiateOMPDeclareSimdDeclAttr(*this, TemplateArgs, *OMPAttr, New);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Existing DLL attribute on the instantiation takes precedence.
|
// Existing DLL attribute on the instantiation takes precedence.
|
||||||
if (TmplAttr->getKind() == attr::DLLExport ||
|
if (TmplAttr->getKind() == attr::DLLExport ||
|
||||||
TmplAttr->getKind() == attr::DLLImport) {
|
TmplAttr->getKind() == attr::DLLImport) {
|
||||||
|
|
|
@ -7,14 +7,14 @@
|
||||||
#define HEADER
|
#define HEADER
|
||||||
|
|
||||||
#pragma omp declare simd
|
#pragma omp declare simd
|
||||||
#pragma omp declare simd
|
#pragma omp declare simd simdlen(32)
|
||||||
#pragma omp declare simd inbranch
|
#pragma omp declare simd inbranch
|
||||||
#pragma omp declare simd notinbranch
|
#pragma omp declare simd notinbranch simdlen(2)
|
||||||
void add_1(float *d, float *s1, float *s2) __attribute__((cold));
|
void add_1(float *d, float *s1, float *s2) __attribute__((cold));
|
||||||
|
|
||||||
// CHECK: #pragma omp declare simd notinbranch
|
// CHECK: #pragma omp declare simd notinbranch simdlen(2)
|
||||||
// CHECK-NEXT: #pragma omp declare simd inbranch
|
// CHECK-NEXT: #pragma omp declare simd inbranch
|
||||||
// CHECK-NEXT: #pragma omp declare simd
|
// CHECK-NEXT: #pragma omp declare simd simdlen(32)
|
||||||
// CHECK-NEXT: #pragma omp declare simd
|
// CHECK-NEXT: #pragma omp declare simd
|
||||||
// CHECK-NEXT: void add_1(float *d, float *s1, float *s2) __attribute__((cold))
|
// CHECK-NEXT: void add_1(float *d, float *s1, float *s2) __attribute__((cold))
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,12 @@
|
||||||
#define HEADER
|
#define HEADER
|
||||||
|
|
||||||
#pragma omp declare simd
|
#pragma omp declare simd
|
||||||
#pragma omp declare simd inbranch
|
#pragma omp declare simd inbranch simdlen(32)
|
||||||
#pragma omp declare simd notinbranch
|
#pragma omp declare simd notinbranch
|
||||||
void add_1(float *d) __attribute__((cold));
|
void add_1(float *d) __attribute__((cold));
|
||||||
|
|
||||||
// CHECK: #pragma omp declare simd notinbranch
|
// CHECK: #pragma omp declare simd notinbranch
|
||||||
// CHECK-NEXT: #pragma omp declare simd inbranch
|
// CHECK-NEXT: #pragma omp declare simd inbranch simdlen(32)
|
||||||
// CHECK-NEXT: #pragma omp declare simd
|
// CHECK-NEXT: #pragma omp declare simd
|
||||||
// CHECK-NEXT: void add_1(float *d) __attribute__((cold));
|
// CHECK-NEXT: void add_1(float *d) __attribute__((cold));
|
||||||
//
|
//
|
||||||
|
@ -92,10 +92,10 @@ template <int X>
|
||||||
class TVV {
|
class TVV {
|
||||||
public:
|
public:
|
||||||
// CHECK: template <int X> class TVV {
|
// CHECK: template <int X> class TVV {
|
||||||
#pragma omp declare simd
|
#pragma omp declare simd simdlen(X)
|
||||||
int tadd(int a, int b) { return a + b; }
|
int tadd(int a, int b) { return a + b; }
|
||||||
|
|
||||||
// CHECK: #pragma omp declare simd
|
// CHECK: #pragma omp declare simd simdlen(X)
|
||||||
// CHECK-NEXT: int tadd(int a, int b) {
|
// CHECK-NEXT: int tadd(int a, int b) {
|
||||||
// CHECK-NEXT: return a + b;
|
// CHECK-NEXT: return a + b;
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
|
@ -123,6 +123,14 @@ private:
|
||||||
};
|
};
|
||||||
// CHECK: };
|
// CHECK: };
|
||||||
|
|
||||||
|
// CHECK: #pragma omp declare simd simdlen(64)
|
||||||
|
// CHECK: template <int N = 64> void foo(int (&)[64])
|
||||||
|
// CHECK: #pragma omp declare simd simdlen(N)
|
||||||
|
// CHECK: template <int N> void foo(int (&)[N])
|
||||||
|
#pragma omp declare simd simdlen(N)
|
||||||
|
template <int N>
|
||||||
|
void foo(int (&)[N]);
|
||||||
|
|
||||||
// CHECK: TVV<16> t16;
|
// CHECK: TVV<16> t16;
|
||||||
TVV<16> t16;
|
TVV<16> t16;
|
||||||
|
|
||||||
|
@ -130,6 +138,8 @@ void f() {
|
||||||
float a = 1.0f, b = 2.0f;
|
float a = 1.0f, b = 2.0f;
|
||||||
float r = t16.taddpf(&a, &b);
|
float r = t16.taddpf(&a, &b);
|
||||||
int res = t16.tadd(b);
|
int res = t16.tadd(b);
|
||||||
|
int c[64];
|
||||||
|
foo(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,9 +32,12 @@ int main();
|
||||||
|
|
||||||
// expected-error@+1 {{single declaration is expected after 'declare simd' directive}}
|
// expected-error@+1 {{single declaration is expected after 'declare simd' directive}}
|
||||||
#pragma omp declare simd
|
#pragma omp declare simd
|
||||||
|
// expected-note@+1 {{declared here}}
|
||||||
int b, c;
|
int b, c;
|
||||||
|
|
||||||
#pragma omp declare simd
|
// expected-error@+1 {{'C' does not refer to a value}}
|
||||||
|
#pragma omp declare simd simdlen(C)
|
||||||
|
// expected-note@+1 {{declared here}}
|
||||||
template <class C>
|
template <class C>
|
||||||
void h(C *hp, C *hp2, C *hq, C *lin) {
|
void h(C *hp, C *hp2, C *hq, C *lin) {
|
||||||
b = 0;
|
b = 0;
|
||||||
|
@ -50,8 +53,38 @@ void h(int *hp, int *hp2, int *hq, int *lin) {
|
||||||
#pragma omp declare simd notinbranch notinbranch
|
#pragma omp declare simd notinbranch notinbranch
|
||||||
#pragma omp declare simd inbranch inbranch notinbranch // expected-error {{unexpected 'notinbranch' clause, 'inbranch' is specified already}}
|
#pragma omp declare simd inbranch inbranch notinbranch // expected-error {{unexpected 'notinbranch' clause, 'inbranch' is specified already}}
|
||||||
#pragma omp declare simd notinbranch notinbranch inbranch // expected-error {{unexpected 'inbranch' clause, 'notinbranch' is specified already}}
|
#pragma omp declare simd notinbranch notinbranch inbranch // expected-error {{unexpected 'inbranch' clause, 'notinbranch' is specified already}}
|
||||||
|
// expected-note@+2 {{read of non-const variable 'b' is not allowed in a constant expression}}
|
||||||
|
// expected-error@+1 {{expression is not an integral constant expression}}
|
||||||
|
#pragma omp declare simd simdlen(b)
|
||||||
|
// expected-error@+1 {{directive '#pragma omp declare simd' cannot contain more than one 'simdlen' clause}}
|
||||||
|
#pragma omp declare simd simdlen(32) simdlen(c)
|
||||||
|
// expected-error@+1 {{expected '(' after 'simdlen'}}
|
||||||
|
#pragma omp declare simd simdlen
|
||||||
|
// expected-note@+3 {{to match this '('}}
|
||||||
|
// expected-error@+2 {{expected ')'}}
|
||||||
|
// expected-error@+1 {{expected expression}}
|
||||||
|
#pragma omp declare simd simdlen(
|
||||||
|
// expected-error@+2 {{expected '(' after 'simdlen'}}
|
||||||
|
// expected-error@+1 {{expected expression}}
|
||||||
|
#pragma omp declare simd simdlen(), simdlen
|
||||||
|
// expected-error@+1 2 {{expected expression}}
|
||||||
|
#pragma omp declare simd simdlen(), simdlen()
|
||||||
|
// expected-warning@+3 {{extra tokens at the end of '#pragma omp declare simd' are ignored}}
|
||||||
|
// expected-error@+2 {{expected '(' after 'simdlen'}}
|
||||||
|
// expected-error@+1 {{expected expression}}
|
||||||
|
#pragma omp declare simd simdlen() simdlen)
|
||||||
void foo();
|
void foo();
|
||||||
|
|
||||||
|
// expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
|
||||||
|
#pragma omp declare simd simdlen(N)
|
||||||
|
template<int N>
|
||||||
|
void foo() {}
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
// expected-note@+1 {{in instantiation of function template specialization 'foo<-3>' requested here}}
|
||||||
|
foo<-3>();
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct St {
|
struct St {
|
||||||
// expected-error@+2 {{function declaration is expected after 'declare simd' directive}}
|
// expected-error@+2 {{function declaration is expected after 'declare simd' directive}}
|
||||||
|
|
|
@ -64,5 +64,5 @@ void foo();
|
||||||
|
|
||||||
// CHECK: `-FunctionDecl {{.+}} <line:63:1, col:10> col:6 foo 'void (void)'
|
// CHECK: `-FunctionDecl {{.+}} <line:63:1, col:10> col:6 foo 'void (void)'
|
||||||
// CHECK-NEXT: |-OMPDeclareSimdDeclAttr {{.+}} <line:62:9, col:34> Implicit BS_Inbranch
|
// CHECK-NEXT: |-OMPDeclareSimdDeclAttr {{.+}} <line:62:9, col:34> Implicit BS_Inbranch
|
||||||
// CHECK-NEXT: `-OMPDeclareSimdDeclAttr {{.+}} <line:61:9, col:25> Implicit BS_Undefined
|
// CHECK: `-OMPDeclareSimdDeclAttr {{.+}} <line:61:9, col:25> Implicit BS_Undefined
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue