[prev in list] [next in list] [prev in thread] [next in thread]
List: cfe-commits
Subject: Re: [PATCH] D10599: [OPENMP 4.0] Initial support for '#pragma omp declare simd' directive.
From: Alexey Bataev <a.bataev () hotmail ! com>
Date: 2015-07-27 4:00:26
Message-ID: 2503f53917c06701f0c8ea00e9c40182 () localhost ! localdomain
[Download RAW message or body]
ABataev updated the summary for this revision.
ABataev updated this revision to Diff 30669.
ABataev added a comment.
Update after review
http://reviews.llvm.org/D10599
Files:
include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/OpenMPKinds.def
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
lib/AST/DeclPrinter.cpp
lib/Basic/OpenMPKinds.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseOpenMP.cpp
lib/Parse/Parser.cpp
lib/Sema/SemaOpenMP.cpp
test/OpenMP/declare_simd_ast_print.c
test/OpenMP/declare_simd_ast_print.cpp
test/OpenMP/declare_simd_messages.cpp
["D10599.30669.patch" (text/x-patch)]
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -652,8 +652,10 @@
case tok::annot_pragma_opencl_extension:
HandlePragmaOpenCLExtension();
return DeclGroupPtrTy();
- case tok::annot_pragma_openmp:
- return ParseOpenMPDeclarativeDirective();
+ case tok::annot_pragma_openmp: {
+ AccessSpecifier AS = AS_none;
+ return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs);
+ }
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
return DeclGroupPtrTy();
Index: lib/Parse/ParseOpenMP.cpp
===================================================================
--- lib/Parse/ParseOpenMP.cpp
+++ lib/Parse/ParseOpenMP.cpp
@@ -31,6 +31,7 @@
// E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd
// TODO: add other combined directives in topological order.
const OpenMPDirectiveKind F[][3] = {
+ {OMPD_unknown /*declare*/, OMPD_simd, OMPD_declare_simd},
{OMPD_unknown /*cancellation*/, OMPD_unknown /*point*/,
OMPD_cancellation_point},
{OMPD_target, OMPD_unknown /*data*/, OMPD_target_data},
@@ -46,13 +47,14 @@
bool TokenMatched = false;
for (unsigned i = 0; i < llvm::array_lengthof(F); ++i) {
- if (!Tok.isAnnotation() && DKind == OMPD_unknown) {
+ if (!Tok.isAnnotation() && DKind == OMPD_unknown)
TokenMatched =
- (i == 0) &&
- !P.getPreprocessor().getSpelling(Tok).compare("cancellation");
- } else {
+ ((i == 0) &&
+ !P.getPreprocessor().getSpelling(Tok).compare("declare")) ||
+ ((i == 1) &&
+ !P.getPreprocessor().getSpelling(Tok).compare("cancellation"));
+ else
TokenMatched = DKind == F[i][0] && DKind != OMPD_unknown;
- }
if (TokenMatched) {
Tok = P.getPreprocessor().LookAhead(0);
@@ -64,12 +66,11 @@
if (!TokenIsAnnotation && SDKind == OMPD_unknown) {
TokenMatched =
- ((i == 0) &&
+ ((i == 1) &&
!P.getPreprocessor().getSpelling(Tok).compare("point")) ||
- ((i == 1) && \
!P.getPreprocessor().getSpelling(Tok).compare("data"));
- } else {
+ ((i == 2) && \
!P.getPreprocessor().getSpelling(Tok).compare("data")); + } else
TokenMatched = SDKind == F[i][1] && SDKind != OMPD_unknown;
- }
if (TokenMatched) {
P.ConsumeToken();
@@ -84,14 +85,25 @@
///
/// threadprivate-directive:
/// annot_pragma_openmp 'threadprivate' simple-variable-list
+/// annot_pragma_omp_end
///
-Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
+/// declare-simd-directive:
+/// annot_pragma_openmp 'declare simd' {<clause> [,]}
+/// annot_pragma_omp_end
+/// <function declaration/definition>
+///
+Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
+ AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
+ DeclSpec::TST TagType, Decl *TagDecl) {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
ParenBraceBracketBalancer BalancerRAIIObj(*this);
+ auto AnnotationVal = \
reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()); SourceLocation Loc \
= ConsumeToken(); SmallVector<Expr *, 5> Identifiers;
- auto DKind = ParseOpenMPDirectiveKind(*this);
+ OpenMPDirectiveKind DKind =
+ (AnnotationVal == 0) ? ParseOpenMPDirectiveKind(*this)
+ : \
static_cast<OpenMPDirectiveKind>(AnnotationVal);
switch (DKind) {
case OMPD_threadprivate:
@@ -109,6 +121,97 @@
return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers);
}
break;
+ case OMPD_declare_simd: {
+ // The syntax is:
+ // { #pragma omp declare simd }
+ // <function-declaration-or-definition>
+ //
+ if (AnnotationVal == 0)
+ // Skip 'simd' if it was restored from cached tokens.
+ ConsumeToken();
+
+ SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + \
1> + FirstClauses(OMPC_unknown + 1);
+ SmallVector<OMPClause *, 4> Clauses;
+ SmallVector<Token, 8> CachedPragmas;
+
+ while (Tok.isNot(tok::annot_pragma_openmp_end) && Tok.isNot(tok::eof)) \
{ + CachedPragmas.push_back(Tok);
+ ConsumeAnyToken();
+ }
+ CachedPragmas.push_back(Tok);
+ if (Tok.isNot(tok::eof))
+ ConsumeAnyToken();
+
+ DeclGroupPtrTy Ptr;
+ if (Tok.is(tok::annot_pragma_openmp))
+ Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, TagType,
+ TagDecl);
+ else
+ // Here we expect to see some function declaration.
+ while (Tok.isNot(tok::r_brace) && !isEofOrEom() &&
+ (!Ptr || Ptr.get().isNull())) {
+ if (AS == AS_none || TagType == DeclSpec::TST_unspecified) {
+ MaybeParseCXX11Attributes(Attrs);
+ MaybeParseMicrosoftAttributes(Attrs);
+ ParsingDeclSpec PDS(*this);
+ Ptr = ParseExternalDeclaration(Attrs, &PDS);
+ } else
+ Ptr = ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, \
TagType, + \
TagDecl); + }
+ if (!Ptr || Ptr.get().isNull()) {
+ if (isEofOrEom())
+ Diag(Loc, diag::err_omp_decl_in_declare_simd);
+ return DeclGroupPtrTy();
+ }
+ if (!Ptr.get().isSingleDecl())
+ Diag(Loc, diag::err_omp_single_decl_in_declare_simd);
+
+ // Append the current token at the end of the new token stream so that \
it + // doesn't get lost.
+ CachedPragmas.push_back(Tok);
+ // Push back tokens for pragma.
+ PP.EnterTokenStream(CachedPragmas.data(), CachedPragmas.size(),
+ /*DisableMacroExpansion=*/true,
+ /*OwnsTokens=*/false);
+ // Parse pragma itself.
+ // Consume the previously pushed token.
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+
+ while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ OpenMPClauseKind CKind = Tok.isAnnotation()
+ ? OMPC_unknown
+ : \
getOpenMPClauseKind(PP.getSpelling(Tok)); + \
Actions.StartOpenMPClause(CKind); + OMPClause *Clause =
+ ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt());
+ FirstClauses[CKind].setInt(true);
+ if (Clause) {
+ FirstClauses[CKind].setPointer(Clause);
+ Clauses.push_back(Clause);
+ }
+
+ // Skip ',' if any.
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ Actions.EndOpenMPClause();
+ }
+ // The last seen token is annot_pragma_openmp_end - 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);
+ SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+ }
+ // Skip the last annot_pragma_openmp_end.
+ ConsumeToken();
+
+ if (Ptr.get().isSingleDecl())
+ return Actions.ActOnOpenMPDeclareSimdDirective(
+ Clauses, Ptr.get().getSingleDecl(), Loc);
+ return Ptr;
+ }
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
break;
@@ -310,6 +413,11 @@
OMPDirectiveScope.Exit();
break;
}
+ case OMPD_declare_simd:
+ Diag(Tok, diag::err_omp_unexpected_directive)
+ << getOpenMPDirectiveName(DKind);
+ SkipUntil(tok::annot_pragma_openmp_end);
+ break;
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
SkipUntil(tok::annot_pragma_openmp_end);
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -2234,8 +2234,9 @@
/// constant-initializer:
/// '=' constant-expression
///
-void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
- AttributeList *AccessAttrs,
+Parser::DeclGroupPtrTy
+Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
+ AttributeList *AccessAttrs,
const ParsedTemplateInfo \
&TemplateInfo,
ParsingDeclRAIIObject \
*TemplateDiags) { if (Tok.is(tok::at)) {
@@ -2246,7 +2247,7 @@
ConsumeToken();
SkipUntil(tok::r_brace, StopAtSemi);
- return;
+ return DeclGroupPtrTy();
}
// Turn on colon protection early, while parsing declspec, although \
there is @@ -2280,52 +2281,49 @@
if (SS.isInvalid()) {
SkipUntil(tok::semi);
- return;
+ return DeclGroupPtrTy();
}
// Try to parse an unqualified-id.
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
if (ParseUnqualifiedId(SS, false, true, true, ParsedType(),
TemplateKWLoc, Name)) {
SkipUntil(tok::semi);
- return;
+ return DeclGroupPtrTy();
}
// TODO: recover from mistakenly-qualified operator declarations.
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
"access declaration")) {
SkipUntil(tok::semi);
- return;
+ return DeclGroupPtrTy();
}
- Actions.ActOnUsingDeclaration(getCurScope(), AS,
- /* HasUsingKeyword */ false,
- SourceLocation(),
- SS, Name,
- /* AttrList */ nullptr,
- /* HasTypenameKeyword */ false,
- SourceLocation());
- return;
+ return DeclGroupPtrTy::make(DeclGroupRef(Actions.ActOnUsingDeclaration(
+ getCurScope(), AS,
+ /* HasUsingKeyword */ false, SourceLocation(), SS, Name,
+ /* AttrList */ nullptr,
+ /* HasTypenameKeyword */ false, SourceLocation())));
}
}
// static_assert-declaration. A templated static_assert declaration is
// diagnosed in Parser::ParseSingleDeclarationAfterTemplate.
if (!TemplateInfo.Kind &&
Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) {
SourceLocation DeclEnd;
- ParseStaticAssertDeclaration(DeclEnd);
- return;
+ return DeclGroupPtrTy::make(
+ DeclGroupRef(ParseStaticAssertDeclaration(DeclEnd)));
}
if (Tok.is(tok::kw_template)) {
assert(!TemplateInfo.TemplateParams &&
"Nested template improperly parsed?");
SourceLocation DeclEnd;
- ParseDeclarationStartingWithTemplate(Declarator::MemberContext, \
DeclEnd,
- AS, AccessAttrs);
- return;
+ return DeclGroupPtrTy::make(
+ DeclGroupRef(ParseDeclarationStartingWithTemplate(
+ Declarator::MemberContext, DeclEnd, AS, AccessAttrs)));
}
// Handle: member-declaration ::= '__extension__' member-declaration
@@ -2357,13 +2355,12 @@
if (Tok.is(tok::kw_namespace)) {
Diag(UsingLoc, diag::err_using_namespace_in_class);
SkipUntil(tok::semi, StopBeforeMatch);
- } else {
- SourceLocation DeclEnd;
- // Otherwise, it must be a using-declaration or an \
alias-declaration.
- ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo,
- UsingLoc, DeclEnd, AS);
+ return DeclGroupPtrTy();
}
- return;
+ SourceLocation DeclEnd;
+ // Otherwise, it must be a using-declaration or an alias-declaration.
+ return DeclGroupPtrTy::make(DeclGroupRef(ParseUsingDeclaration(
+ Declarator::MemberContext, TemplateInfo, UsingLoc, DeclEnd, AS)));
}
// Hold late-parsed attributes so we can attach a Decl to them later.
@@ -2388,7 +2385,7 @@
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate &&
DiagnoseMissingSemiAfterTagDefinition(DS, AS, DSC_class,
&CommonLateParsedAttrs))
- return;
+ return DeclGroupPtrTy();
MultiTemplateParamsArg TemplateParams(
TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data()
@@ -2402,7 +2399,7 @@
Decl *TheDecl =
Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, \
TemplateParams); DS.complete(TheDecl);
- return;
+ return DeclGroupPtrTy::make(DeclGroupRef(TheDecl));
}
ParsingDeclarator DeclaratorInfo(*this, DS, Declarator::MemberContext);
@@ -2443,7 +2440,7 @@
if (ParseCXXMemberDeclaratorBeforeInitializer(
DeclaratorInfo, VS, BitfieldSize, LateParsedAttrs)) {
TryConsumeToken(tok::semi);
- return;
+ return DeclGroupPtrTy();
}
// Check for a member function definition.
@@ -2492,7 +2489,7 @@
// Consume the optional ';'
TryConsumeToken(tok::semi);
- return;
+ return DeclGroupPtrTy();
}
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
@@ -2521,7 +2518,7 @@
if (Tok.is(tok::semi))
ConsumeExtraSemi(AfterMemberFunctionDefinition);
- return;
+ return DeclGroupPtrTy::make(DeclGroupRef(FunDecl));
}
}
@@ -2695,10 +2692,10 @@
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
// If we stopped at a ';', eat it.
TryConsumeToken(tok::semi);
- return;
+ return DeclGroupPtrTy();
}
- Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
+ return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
}
/// ParseCXXMemberInitializer - Parse the brace-or-equal-initializer.
@@ -2816,6 +2813,96 @@
MaybeParseGNUAttributes(Attrs);
}
+Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
+ AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs,
+ DeclSpec::TST TagType, Decl *TagDecl) {
+ if (getLangOpts().MicrosoftExt &&
+ Tok.isOneOf(tok::kw___if_exists, tok::kw___if_not_exists)) {
+ ParseMicrosoftIfExistsClassDeclaration(TagType, AS);
+ return DeclGroupPtrTy();
+ }
+
+ // Check for extraneous top-level semicolon.
+ if (Tok.is(tok::semi)) {
+ ConsumeExtraSemi(InsideStruct, TagType);
+ return DeclGroupPtrTy();
+ }
+
+ if (Tok.is(tok::annot_pragma_vis)) {
+ HandlePragmaVisibility();
+ return DeclGroupPtrTy();
+ }
+
+ if (Tok.is(tok::annot_pragma_pack)) {
+ HandlePragmaPack();
+ return DeclGroupPtrTy();
+ }
+
+ if (Tok.is(tok::annot_pragma_align)) {
+ HandlePragmaAlign();
+ return DeclGroupPtrTy();
+ }
+
+ if (Tok.is(tok::annot_pragma_ms_pointers_to_members)) {
+ HandlePragmaMSPointersToMembers();
+ return DeclGroupPtrTy();
+ }
+
+ if (Tok.is(tok::annot_pragma_ms_pragma)) {
+ HandlePragmaMSPragma();
+ return DeclGroupPtrTy();
+ }
+
+ // If we see a namespace here, a close brace was missing somewhere.
+ if (Tok.is(tok::kw_namespace)) {
+ DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl));
+ return DeclGroupPtrTy();
+ }
+
+ AccessSpecifier NewAS = getAccessSpecifierIfPresent();
+ if (NewAS != AS_none) {
+ // Current token is a C++ access specifier.
+ AS = NewAS;
+ SourceLocation ASLoc = Tok.getLocation();
+ unsigned TokLength = Tok.getLength();
+ ConsumeToken();
+ AccessAttrs.clear();
+ MaybeParseGNUAttributes(AccessAttrs);
+
+ SourceLocation EndLoc;
+ if (TryConsumeToken(tok::colon, EndLoc)) {
+ } else if (TryConsumeToken(tok::semi, EndLoc)) {
+ Diag(EndLoc, diag::err_expected)
+ << tok::colon << FixItHint::CreateReplacement(EndLoc, ":");
+ } else {
+ EndLoc = ASLoc.getLocWithOffset(TokLength);
+ Diag(EndLoc, diag::err_expected)
+ << tok::colon << FixItHint::CreateInsertion(EndLoc, ":");
+ }
+
+ // The Microsoft extension __interface does not permit non-public
+ // access specifiers.
+ if (TagType == DeclSpec::TST_interface && AS != AS_public) {
+ Diag(ASLoc, diag::err_access_specifier_interface) << (AS == \
AS_protected); + }
+
+ if (Actions.ActOnAccessSpecifier(NewAS, ASLoc, EndLoc,
+ AccessAttrs.getList())) {
+ // found another attribute than only annotations
+ AccessAttrs.clear();
+ }
+
+ return DeclGroupPtrTy();
+ }
+
+ if (Tok.is(tok::annot_pragma_openmp))
+ return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, AccessAttrs, \
TagType, + TagDecl);
+
+ // Parse all the comma separated declarators.
+ return ParseCXXClassMemberDeclaration(AS, AccessAttrs.getList());
+}
+
/// ParseCXXMemberSpecification - Parse the class definition.
///
/// member-specification:
@@ -2973,101 +3060,14 @@
CurAS = AS_private;
else
CurAS = AS_public;
- ParsedAttributes AccessAttrs(AttrFactory);
+ ParsedAttributesWithRange AccessAttrs(AttrFactory);
if (TagDecl) {
// While we still have something to read, read the \
member-declarations.
- while (Tok.isNot(tok::r_brace) && !isEofOrEom()) {
+ while (Tok.isNot(tok::r_brace) && !isEofOrEom())
// Each iteration of this loop reads one member-declaration.
-
- if (getLangOpts().MicrosoftExt && Tok.isOneOf(tok::kw___if_exists,
- \
tok::kw___if_not_exists)) {
- ParseMicrosoftIfExistsClassDeclaration((DeclSpec::TST)TagType, \
CurAS);
- continue;
- }
-
- // Check for extraneous top-level semicolon.
- if (Tok.is(tok::semi)) {
- ConsumeExtraSemi(InsideStruct, TagType);
- continue;
- }
-
- if (Tok.is(tok::annot_pragma_vis)) {
- HandlePragmaVisibility();
- continue;
- }
-
- if (Tok.is(tok::annot_pragma_pack)) {
- HandlePragmaPack();
- continue;
- }
-
- if (Tok.is(tok::annot_pragma_align)) {
- HandlePragmaAlign();
- continue;
- }
-
- if (Tok.is(tok::annot_pragma_openmp)) {
- ParseOpenMPDeclarativeDirective();
- continue;
- }
-
- if (Tok.is(tok::annot_pragma_ms_pointers_to_members)) {
- HandlePragmaMSPointersToMembers();
- continue;
- }
-
- if (Tok.is(tok::annot_pragma_ms_pragma)) {
- HandlePragmaMSPragma();
- continue;
- }
-
- // If we see a namespace here, a close brace was missing somewhere.
- if (Tok.is(tok::kw_namespace)) {
- DiagnoseUnexpectedNamespace(cast<NamedDecl>(TagDecl));
- break;
- }
-
- AccessSpecifier AS = getAccessSpecifierIfPresent();
- if (AS != AS_none) {
- // Current token is a C++ access specifier.
- CurAS = AS;
- SourceLocation ASLoc = Tok.getLocation();
- unsigned TokLength = Tok.getLength();
- ConsumeToken();
- AccessAttrs.clear();
- MaybeParseGNUAttributes(AccessAttrs);
-
- SourceLocation EndLoc;
- if (TryConsumeToken(tok::colon, EndLoc)) {
- } else if (TryConsumeToken(tok::semi, EndLoc)) {
- Diag(EndLoc, diag::err_expected)
- << tok::colon << FixItHint::CreateReplacement(EndLoc, ":");
- } else {
- EndLoc = ASLoc.getLocWithOffset(TokLength);
- Diag(EndLoc, diag::err_expected)
- << tok::colon << FixItHint::CreateInsertion(EndLoc, ":");
- }
-
- // The Microsoft extension __interface does not permit non-public
- // access specifiers.
- if (TagType == DeclSpec::TST_interface && CurAS != AS_public) {
- Diag(ASLoc, diag::err_access_specifier_interface)
- << (CurAS == AS_protected);
- }
-
- if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc,
- AccessAttrs.getList())) {
- // found another attribute than only annotations
- AccessAttrs.clear();
- }
-
- continue;
- }
-
- // Parse all the comma separated declarators.
- ParseCXXClassMemberDeclaration(CurAS, AccessAttrs.getList());
- }
+ ParseCXXClassMemberDeclarationWithPragmas(
+ CurAS, AccessAttrs, static_cast<DeclSpec::TST>(TagType), \
TagDecl);
T.consumeClose();
} else {
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -36,6 +36,7 @@
void ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls);
void Print(AccessSpecifier AS);
+ void printOMPDeclareSimdAttr(Decl *D);
/// Print an Objective-C method type in parentheses.
///
@@ -202,7 +203,8 @@
AttrVec &Attrs = D->getAttrs();
for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; \
++i) { Attr *A = *i;
- A->printPretty(Out, Policy);
+ if (!isa<OMPDeclareSimdDeclAttr>(A))
+ A->printPretty(Out, Policy);
}
}
}
@@ -407,7 +409,18 @@
}
}
+void DeclPrinter::printOMPDeclareSimdAttr(Decl *D) {
+ for (auto *Attr : D->specific_attrs<OMPDeclareSimdDeclAttr>())
+ Attr->printPrettyPragma(Out, Policy);
+ if (D->hasAttr<OMPDeclareSimdDeclAttr>())
+ Indent();
+}
+
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
+ if (!D->getDescribedFunctionTemplate() &&
+ !D->isFunctionTemplateSpecialization())
+ printOMPDeclareSimdAttr(D);
+
CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
if (!Policy.SuppressSpecifiers) {
@@ -914,11 +927,13 @@
if (PrintInstantiation) {
TemplateParameterList *Params = D->getTemplateParameters();
for (auto *I : D->specializations()) {
+ printOMPDeclareSimdAttr(I);
PrintTemplateParameters(Params, I->getTemplateSpecializationArgs());
Visit(I);
}
}
+ printOMPDeclareSimdAttr(D->getTemplatedDecl());
return VisitRedeclarableTemplateDecl(D);
}
Index: lib/Sema/SemaOpenMP.cpp
===================================================================
--- lib/Sema/SemaOpenMP.cpp
+++ lib/Sema/SemaOpenMP.cpp
@@ -1336,6 +1336,7 @@
case OMPD_cancellation_point:
case OMPD_cancel:
case OMPD_flush:
+ case OMPD_declare_simd:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
@@ -2130,6 +2131,7 @@
EndLoc);
break;
case OMPD_threadprivate:
+ case OMPD_declare_simd:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
@@ -2147,6 +2149,24 @@
return Res;
}
+Sema::DeclGroupPtrTy
+Sema::ActOnOpenMPDeclareSimdDirective(ArrayRef<OMPClause *> Clauses,
+ Decl *ADecl, SourceLocation \
StartLoc) { + 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();
+ return DeclGroupPtrTy();
+ }
+
+ auto *NewAttr = new (Context) OMPDeclareSimdDeclAttr(
+ SourceRange(StartLoc, StartLoc), Context, /*SI=*/0);
+ ADecl->addAttr(NewAttr);
+ return ConvertDeclToDeclGroup(ADecl);
+}
+
StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> \
Clauses, Stmt *AStmt,
SourceLocation StartLoc,
Index: lib/Basic/OpenMPKinds.cpp
===================================================================
--- lib/Basic/OpenMPKinds.cpp
+++ lib/Basic/OpenMPKinds.cpp
@@ -348,6 +348,8 @@
break;
}
break;
+ case OMPD_declare_simd:
+ break;
case OMPD_unknown:
case OMPD_threadprivate:
case OMPD_section:
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -2385,9 +2385,13 @@
LateParsedAttrList \
&LateAttrs); void MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(Declarator \
&D,
\
VirtSpecifiers &VS);
- void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList \
*Attr,
- const ParsedTemplateInfo &TemplateInfo = \
ParsedTemplateInfo(),
- ParsingDeclRAIIObject *DiagsFromTParams = nullptr);
+ DeclGroupPtrTy ParseCXXClassMemberDeclaration(
+ AccessSpecifier AS, AttributeList *Attr,
+ const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
+ ParsingDeclRAIIObject *DiagsFromTParams = nullptr);
+ DeclGroupPtrTy ParseCXXClassMemberDeclarationWithPragmas(
+ AccessSpecifier &AS, ParsedAttributesWithRange &AccessAttrs,
+ DeclSpec::TST TagType, Decl *TagDecl);
void ParseConstructorInitializer(Decl *ConstructorDecl);
MemInitResult ParseMemInitializer(Decl *ConstructorDecl);
void HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
@@ -2416,7 +2420,10 @@
//===--------------------------------------------------------------------===//
// OpenMP: Directives and clauses.
/// \brief Parses declarative OpenMP directives.
- DeclGroupPtrTy ParseOpenMPDeclarativeDirective();
+ DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl(
+ AccessSpecifier &AS, ParsedAttributesWithRange &Attrs,
+ DeclSpec::TST TagType = DeclSpec::TST_unspecified,
+ Decl *TagDecl = nullptr);
/// \brief Parses simple list of variables.
///
/// \param Kind Kind of the directive.
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -144,6 +144,7 @@
class ObjCPropertyDecl;
class ObjCProtocolDecl;
class OMPThreadPrivateDecl;
+ class OMPDeclareSimdDecl;
class OMPClause;
class OverloadCandidateSet;
class OverloadExpr;
@@ -7875,6 +7876,12 @@
SourceLocation EndLoc,
OpenMPDirectiveKind CancelRegion);
+ /// \brief Called on well-formed '\#pragma omp declare simd' after \
parsing of + /// the associated method/function.
+ DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective(ArrayRef<OMPClause *> \
Clauses, + Decl *ADecl,
+ SourceLocation StartLoc);
+
OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
Expr *Expr,
SourceLocation StartLoc,
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7648,6 +7648,8 @@
"the 'copyprivate' clause must not be used with the 'nowait' clause">;
def note_omp_nowait_clause_here : Note<
"'nowait' clause is here">;
+def err_omp_function_expected : Error<
+ "'#pragma omp declare simd' can be applied to functions only">;
def err_omp_wrong_cancel_region : Error<
"one of 'for', 'parallel', 'sections' or 'taskgroup' is expected">;
def err_omp_parent_cancel_region_nowait : Error<
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -989,6 +989,10 @@
"'#pragma omp %0' cannot be an immediate substatement">;
def err_omp_expected_identifier_for_critical : Error<
"expected identifier specifying the name of the 'omp critical' \
directive">; +def err_omp_single_decl_in_declare_simd : Error<
+ "single declaration is expected with 'declare simd' directive">;
+def err_omp_decl_in_declare_simd : Error<
+ "function declaration is expected with 'declare simd' directive">;
// Pragma loop support.
def err_pragma_loop_missing_argument : Error<
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -1610,3 +1610,33 @@
arguments, with arbitrary offsets.
}];
}
+
+def OMPDeclareSimdDocs : Documentation {
+ let Category = DocCatStmt;
+ let Heading = "#pragma omp declare simd";
+ let Content = [{
+The declare simd construct can be applied to a function to enable the \
creation of one or more versions that can process multiple arguments using \
SIMD instructions from a single invocation from a SIMD loop. The declare \
simd directive is a declarative directive. There may be multiple declare \
simd directives for a function. The use of a declare simd construct on a \
function enables the creation of SIMD +versions of the associated function \
that can be used to process multiple arguments from a single invocation \
from a SIMD loop concurrently. +The syntax of the declare simd construct is \
as follows: +
+ .. code-block:: c
+
+ #pragma omp declare simd [clause[[,] clause] ...] new-line
+ [#pragma omp declare simd [clause[[,] clause] ...] new-line]
+ [...]
+ function definition or declaration
+
+where clause is one of the following:
+
+ .. code-block:: c
+
+ simdlen(length)
+ linear(argument-list[:constant-linear-step])
+ aligned(argument-list[:alignment])
+ uniform(argument-list)
+ inbranch
+ notinbranch
+
+ }];
+}
+
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -2064,3 +2064,17 @@
let SemaHandler = 0;
let Documentation = [Undocumented];
}
+
+def OMPDeclareSimdDecl : Attr {
+ let Spellings = [Pragma<"omp", "declare simd">];
+ let Subjects = SubjectList<[Function]>;
+ let SemaHandler = 0;
+ let HasCustomParsing = 1;
+ let Documentation = [OMPDeclareSimdDocs];
+ let AdditionalMembers = [{
+ void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) \
const { + OS << "#pragma omp declare simd\n";
+ }
+ }];
+}
+
Index: include/clang/Basic/OpenMPKinds.def
===================================================================
--- include/clang/Basic/OpenMPKinds.def
+++ include/clang/Basic/OpenMPKinds.def
@@ -103,6 +103,7 @@
OPENMP_DIRECTIVE_EXT(parallel_sections, "parallel sections")
OPENMP_DIRECTIVE_EXT(for_simd, "for simd")
OPENMP_DIRECTIVE_EXT(cancellation_point, "cancellation point")
+OPENMP_DIRECTIVE_EXT(declare_simd, "declare simd")
// OpenMP clauses.
OPENMP_CLAUSE(if, OMPIfClause)
Index: test/OpenMP/declare_simd_ast_print.c
===================================================================
--- test/OpenMP/declare_simd_ast_print.c
+++ test/OpenMP/declare_simd_ast_print.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -include-pch %t -fsyntax-only -verify %s \
-ast-print | FileCheck %s +// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+#pragma omp declare simd
+#pragma omp declare simd
+void add_1(float *d, float *s1, float *s2);
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: #pragma omp declare simd
+// CHECK-NEXT: void add_1(float *d, float *s1, float *s2)
+
+#endif
Index: test/OpenMP/declare_simd_ast_print.cpp
===================================================================
--- test/OpenMP/declare_simd_ast_print.cpp
+++ test/OpenMP/declare_simd_ast_print.cpp
@@ -0,0 +1,144 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -ast-print %s | \
FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t \
%s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -include-pch %t \
-fsyntax-only -verify %s -ast-print | FileCheck %s +// \
expected-no-diagnostics +
+#ifndef HEADER
+#define HEADER
+
+#pragma omp declare simd
+void add_1(float *d);
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: void add_1(float *d);
+//
+
+#pragma omp declare simd
+template <class C> void h(C *hp, C *hp2, C *hq, C *lin) {
+}
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: template <class C = int> void h(int *hp, int *hp2, int *hq, \
int *lin) { +// CHECK-NEXT: h((float *)hp, (float *)hp2, (float *)hq, \
(float *)lin); +// CHECK-NEXT: }
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: template <class C = float> void h(float *hp, float *hp2, \
float *hq, float *lin) { +// CHECK-NEXT: }
+
+// CHECK: #pragma omp declare simd
+// CHECK: template <class C> void h(C *hp, C *hp2, C *hq, C *lin) {
+// CHECK-NEXT: }
+//
+
+// Explicit specialization with <C=int>.
+// Pragmas need to be same, otherwise standard says that's undefined \
behavior. +#pragma omp declare simd
+template <>
+void h(int *hp, int *hp2, int *hq, int *lin)
+{
+ // Implicit specialization with <C=float>.
+ // This is special case where the directive is stored by Sema and is
+ // generated together with the (pending) function instatiation.
+ h((float*) hp, (float*) hp2, (float*) hq, (float*) lin);
+}
+
+class VV {
+ // CHECK: #pragma omp declare simd
+ // CHECK-NEXT: int add(int a, int b) {
+ // CHECK-NEXT: return a + b;
+ // CHECK-NEXT: }
+ #pragma omp declare simd
+ int add(int a, int b) { return a + b; }
+
+ // CHECK: #pragma omp declare simd
+ // CHECK-NEXT: float taddpf(float *a, float *b) {
+ // CHECK-NEXT: return *a + *b;
+ // CHECK-NEXT: }
+ #pragma options align=packed
+ #pragma GCC visibility push(default)
+ #pragma omp declare simd
+ float taddpf(float *a, float *b) { return *a + *b; }
+ #pragma GCC visibility pop
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: #pragma omp declare simd
+// CHECK-NEXT: int tadd(int b) {
+// CHECK-NEXT: return this->x[b] + b;
+// CHECK-NEXT: }
+ #pragma omp declare simd
+ #pragma GCC visibility push(default)
+ #pragma options align=packed
+ #pragma omp declare simd
+ #pragma GCC visibility pop
+ int tadd(int b) { return x[b] + b; }
+
+private:
+ int x[10];
+};
+
+// CHECK: template <int X = 16> class TVV {
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: int tadd(int a, int b);
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: float taddpf(float *a, float *b) {
+// CHECK-NEXT: return *a + *b;
+// CHECK-NEXT: }
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: #pragma omp declare simd
+// CHECK-NEXT: int tadd(int b) {
+// CHECK-NEXT: return this->x[b] + b;
+// CHECK-NEXT: }
+// CHECK: }
+template <int X>
+class TVV {
+public:
+// CHECK: template <int X> class TVV {
+ #pragma omp declare simd
+ int tadd(int a, int b) { return a + b; }
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: int tadd(int a, int b) {
+// CHECK-NEXT: return a + b;
+// CHECK-NEXT: }
+
+
+ #pragma options align=packed
+ #pragma GCC visibility push(default)
+ #pragma omp declare simd
+ float taddpf(float *a, float *b) { return *a + *b; }
+ #pragma GCC visibility pop
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: float taddpf(float *a, float *b) {
+// CHECK-NEXT: return *a + *b;
+// CHECK-NEXT: }
+
+ #pragma omp declare simd
+ #pragma GCC visibility push(default)
+ #pragma options align=packed
+ #pragma omp declare simd
+ #pragma GCC visibility pop
+ int tadd(int b) { return x[b] + b; }
+
+// CHECK: #pragma omp declare simd
+// CHECK-NEXT: #pragma omp declare simd
+// CHECK-NEXT: int tadd(int b) {
+// CHECK-NEXT: return this->x[b] + b;
+// CHECK-NEXT: }
+
+private:
+ int x[X];
+};
+// CHECK: };
+
+// CHECK: TVV<16> t16;
+TVV<16> t16;
+
+void f() {
+ float a = 1.0f, b = 2.0f;
+ float r = t16.taddpf(&a, &b);
+ int res = t16.tadd(b);
+}
+
+#endif
Index: test/OpenMP/declare_simd_messages.cpp
===================================================================
--- test/OpenMP/declare_simd_messages.cpp
+++ test/OpenMP/declare_simd_messages.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -x \
c++ -std=c++11 %s +
+// expected-error@+1 {{expected an OpenMP directive}}
+#pragma omp declare
+
+// expected-error@+2 {{'#pragma omp declare simd' can be applied to \
functions only}} +#pragma omp declare simd
+int a;
+// expected-error@+2 {{'#pragma omp declare simd' can be applied to \
functions only}} +#pragma omp declare simd
+#pragma omp threadprivate(a)
+int var;
+#pragma omp threadprivate(var)
+
+// expected-error@+2 {{expected an OpenMP directive}}
+#pragma omp declare simd
+#pragma omp declare
+
+#pragma omp declare simd
+#pragma omp declare simd
+int main();
+
+// expected-error@+1 {{single declaration is expected with 'declare simd' \
directive}} +#pragma omp declare simd
+int b, c;
+
+#pragma omp declare simd
+template <class C>
+void h(C *hp, C *hp2, C *hq, C *lin) {
+ b = 0;
+}
+
+#pragma omp declare simd
+template <>
+void h(int *hp, int *hp2, int *hq, int *lin) {
+ h((float *)hp, (float *)hp2, (float *)hq, (float *)lin);
+}
+
+template <class T>
+struct St {
+#pragma omp declare simd
+ void h(T *hp) {
+// expected-error@+1 {{unexpected OpenMP directive '#pragma omp declare \
simd'}} +#pragma omp declare simd
+ *hp = *t;
+ }
+
+private:
+ T t;
+};
+// expected-error@+1 {{function declaration is expected with 'declare \
simd' directive}} +#pragma omp declare simd
+// expected-error@+1 {{function declaration is expected with 'declare \
simd' directive}} +#pragma omp declare simd
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic