[prev in list] [next in list] [prev in thread] [next in thread]
List: cfe-commits
Subject: Re: [PATCH] D11182: [OPENMP 4.0] Initial support for 'omp declare reduction' construct.
From: Alexey Bataev <a.bataev () hotmail ! com>
Date: 2015-07-29 12:18:37
Message-ID: a8e92d74e6a844f01b870ff80b87749a () localhost ! localdomain
[Download RAW message or body]
ABataev updated this revision to Diff 30891.
ABataev added a comment.
Update after review
http://reviews.llvm.org/D11182
Files:
include/clang/AST/DataRecursiveASTVisitor.h
include/clang/AST/DeclBase.h
include/clang/AST/DeclOpenMP.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/Basic/DeclNodes.td
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/OpenMPKinds.def
include/clang/Parse/Parser.h
include/clang/Sema/ScopeInfo.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/ASTContext.cpp
lib/AST/Decl.cpp
lib/AST/DeclBase.cpp
lib/AST/DeclOpenMP.cpp
lib/AST/DeclPrinter.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/MicrosoftMangle.cpp
lib/Basic/OpenMPKinds.cpp
lib/CodeGen/CGDecl.cpp
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseOpenMP.cpp
lib/Parse/Parser.cpp
lib/Sema/ScopeInfo.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaOpenMP.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Serialization/ASTCommon.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/OpenMP/declare_reduction_ast_print.c
test/OpenMP/declare_reduction_ast_print.cpp
test/OpenMP/declare_reduction_messages.c
test/OpenMP/declare_reduction_messages.cpp
tools/libclang/CIndex.cpp
["D11182.30891.patch" (text/x-patch)]
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -131,6 +131,7 @@
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
+ void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
/// Add an Objective-C type parameter list to the given record.
void AddObjCTypeParamList(ObjCTypeParamList *typeParams) {
@@ -1544,6 +1545,15 @@
Code = serialization::DECL_OMP_THREADPRIVATE;
}
+void ASTDeclWriter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
+ VisitDeclaratorDecl(D);
+ Writer.AddSourceLocation(D->getLocStart(), Record);
+ Writer.AddStmt(D->getCombiner());
+ Writer.AddStmt(D->getInitializer());
+ Writer.AddDeclRef(D->getNextDeclInScope(), Record);
+ Code = serialization::DECL_OMP_DECLARE_REDUCTION;
+}
+
//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -381,6 +381,7 @@
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
+ void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
/// We've merged the definition \p MergedDef into the existing definition
/// \p Def. Ensure that \p Def is made visible whenever \p MergedDef is made
@@ -2376,6 +2377,14 @@
D->setVars(Vars);
}
+void ASTDeclReader::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
+ VisitDeclaratorDecl(D);
+ D->setLocation(Reader.ReadSourceLocation(F, Record, Idx));
+ D->setCombiner(Reader.ReadExpr(F));
+ D->setInitializer(Reader.ReadExpr(F));
+ D->setNextDeclInScope(ReadDeclAs<OMPDeclareReductionDecl>(Record, Idx));
+}
+
//===----------------------------------------------------------------------===//
// Attribute Reading
//===----------------------------------------------------------------------===//
@@ -2425,7 +2434,8 @@
isa<ObjCProtocolDecl>(D) ||
isa<ObjCImplDecl>(D) ||
isa<ImportDecl>(D) ||
- isa<OMPThreadPrivateDecl>(D))
+ isa<OMPThreadPrivateDecl>(D) ||
+ isa<OMPDeclareReductionDecl>(D))
return true;
if (VarDecl *Var = dyn_cast<VarDecl>(D))
return Var->isFileVarDecl() &&
@@ -3312,6 +3322,9 @@
case DECL_OMP_THREADPRIVATE:
D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, Record[Idx++]);
break;
+ case DECL_OMP_DECLARE_REDUCTION:
+ D = OMPDeclareReductionDecl::CreateDeserialized(Context, ID);
+ break;
case DECL_EMPTY:
D = EmptyDecl::CreateDeserialized(Context, ID);
break;
Index: lib/Serialization/ASTCommon.cpp
===================================================================
--- lib/Serialization/ASTCommon.cpp
+++ lib/Serialization/ASTCommon.cpp
@@ -215,6 +215,7 @@
case Decl::ClassScopeFunctionSpecialization:
case Decl::Import:
case Decl::OMPThreadPrivate:
+ case Decl::OMPDeclareReduction:
return false;
// These indirectly derive from Redeclarable<T> but are not actually
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -653,7 +653,7 @@
HandlePragmaOpenCLExtension();
return DeclGroupPtrTy();
case tok::annot_pragma_openmp:
- return ParseOpenMPDeclarativeDirective();
+ return ParseOpenMPDeclarativeDirective(/*AS=*/AS_none);
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
return DeclGroupPtrTy();
Index: lib/Parse/ParseOpenMP.cpp
===================================================================
--- lib/Parse/ParseOpenMP.cpp
+++ lib/Parse/ParseOpenMP.cpp
@@ -33,6 +33,8 @@
const OpenMPDirectiveKind F[][3] = {
{OMPD_unknown /*cancellation*/, OMPD_unknown /*point*/,
OMPD_cancellation_point},
+ {OMPD_unknown /*declare*/, OMPD_unknown /*reduction*/,
+ OMPD_declare_reduction},
{OMPD_target, OMPD_unknown /*data*/, OMPD_target_data},
{OMPD_for, OMPD_simd, OMPD_for_simd},
{OMPD_parallel, OMPD_for, OMPD_parallel_for},
@@ -46,30 +48,31 @@
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("cancellation")) ||
+ ((i == 1) &&
+ !P.getPreprocessor().getSpelling(Tok).compare("declare"));
+ else
TokenMatched = DKind == F[i][0] && DKind != OMPD_unknown;
- }
if (TokenMatched) {
Tok = P.getPreprocessor().LookAhead(0);
auto TokenIsAnnotation = Tok.isAnnotation();
auto SDKind =
TokenIsAnnotation
? OMPD_unknown
: getOpenMPDirectiveKind(P.getPreprocessor().getSpelling(Tok));
-
- if (!TokenIsAnnotation && SDKind == OMPD_unknown) {
+ if (!Tok.isAnnotation() && SDKind == OMPD_unknown)
TokenMatched =
((i == 0) &&
!P.getPreprocessor().getSpelling(Tok).compare("point")) ||
- ((i == 1) && !P.getPreprocessor().getSpelling(Tok).compare("data"));
- } else {
+ ((i == 1) &&
+ !P.getPreprocessor().getSpelling(Tok).compare("reduction")) ||
+ ((i == 2) && !P.getPreprocessor().getSpelling(Tok).compare("data"));
+ else
TokenMatched = SDKind == F[i][1] && SDKind != OMPD_unknown;
- }
if (TokenMatched) {
P.ConsumeToken();
@@ -80,12 +83,261 @@
return DKind;
}
+static DeclarationName parseOpenMPReductionId(Parser &P) {
+ DeclarationName Name;
+ const Token &Tok = P.getCurToken();
+ Sema &Actions = P.getActions();
+ switch (Tok.getKind()) {
+ case tok::plus: // '+'
+ Name = Actions.getASTContext().DeclarationNames.getIdentifier(
+ &Actions.Context.Idents.get("+"));
+ P.ConsumeToken();
+ break;
+ case tok::minus: // '-'
+ Name = Actions.getASTContext().DeclarationNames.getIdentifier(
+ &Actions.Context.Idents.get("-"));
+ P.ConsumeToken();
+ break;
+ case tok::star: // '*'
+ Name = Actions.getASTContext().DeclarationNames.getIdentifier(
+ &Actions.Context.Idents.get("*"));
+ P.ConsumeToken();
+ break;
+ case tok::amp: // '&'
+ Name = Actions.getASTContext().DeclarationNames.getIdentifier(
+ &Actions.Context.Idents.get("&"));
+ P.ConsumeToken();
+ break;
+ case tok::pipe: // '|'
+ Name = Actions.getASTContext().DeclarationNames.getIdentifier(
+ &Actions.Context.Idents.get("|"));
+ P.ConsumeToken();
+ break;
+ case tok::caret: // '^'
+ Name = Actions.getASTContext().DeclarationNames.getIdentifier(
+ &Actions.Context.Idents.get("^"));
+ P.ConsumeToken();
+ break;
+ case tok::ampamp: // '&&'
+ Name = Actions.getASTContext().DeclarationNames.getIdentifier(
+ &Actions.Context.Idents.get("&&"));
+ P.ConsumeToken();
+ break;
+ case tok::pipepipe: // '||'
+ Name = Actions.getASTContext().DeclarationNames.getIdentifier(
+ &Actions.Context.Idents.get("||"));
+ P.ConsumeToken();
+ break;
+ case tok::identifier: // identifier
+ Name = Actions.getASTContext().DeclarationNames.getIdentifier(
+ Tok.getIdentifierInfo());
+ P.ConsumeToken();
+ break;
+ default:
+ P.Diag(Tok.getLocation(), diag::err_omp_expected_reduction_identifier);
+ P.SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
+ Parser::StopBeforeMatch);
+ break;
+ }
+ return Name;
+}
+
+/// \brief Parse 'omp declare reduction' construct.
+///
+/// declare-reduction-directive:
+/// annot_pragma_openmp 'declare' 'reduction'
+/// '(' <reduction_id> ':' <type> {',' <type>} ':' <expression> ')'
+/// ['initializer' '(' ('omp_priv' '=' <expression>)|<function_call> ')']
+/// annot_pragma_openmp_end
+/// <reduction_id> is either a base language identifier or one of the following
+/// operators: '+', '-', '*', '&', '|', '^', '&&' and '||'.
+///
+Parser::DeclGroupPtrTy
+Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
+ // Parse '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPDirectiveName(OMPD_declare_reduction))) {
+ SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+ return DeclGroupPtrTy();
+ }
+
+ DeclarationName Name = parseOpenMPReductionId(*this);
+ if (Name.isEmpty() && Tok.is(tok::annot_pragma_openmp_end))
+ return DeclGroupPtrTy();
+ bool IsCorrect = true;
+
+ // Consume ':'.
+ if (Tok.is(tok::colon)) {
+ ConsumeAnyToken();
+ } else {
+ Diag(Tok.getLocation(), diag::err_expected) << "':'";
+ IsCorrect = false;
+ }
+
+ if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))
+ return DeclGroupPtrTy();
+
+ if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) {
+ Diag(Tok.getLocation(), diag::err_expected_type);
+ IsCorrect = false;
+ }
+
+ if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))
+ return DeclGroupPtrTy();
+
+ SmallVector<std::pair<QualType, SourceLocation>, 8> ReductionTypes;
+ SmallVector<std::pair<Expr *, Expr *>, 8> CombinersInitializers;
+ bool IsCommaFound = false;
+ bool FunctionsCorrect = true;
+ // Parse list of types until ':' token.
+ while (Tok.isNot(tok::colon) && Tok.isNot(tok::annot_pragma_openmp_end)) {
+ ColonProtectionRAIIObject ColonRAII(*this);
+ IsCommaFound = false;
+ SourceRange Range;
+ TypeResult TR = ParseTypeName(&Range, Declarator::PrototypeContext, AS);
+ if (TR.isUsable()) {
+ QualType ReductionType = Sema::GetTypeFromParser(TR.get());
+ if (!ReductionType.isNull() &&
+ Actions.isOpenMPDeclareReductionTypeAllowed(
+ Range.getBegin(), ReductionType, ReductionTypes))
+ ReductionTypes.push_back(
+ std::make_pair(ReductionType, Range.getBegin()));
+ else
+ FunctionsCorrect = false;
+ } else {
+ SkipUntil(tok::comma, tok::colon, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ FunctionsCorrect = false;
+ }
+
+ // Consume ','.
+ if (Tok.is(tok::comma)) {
+ ConsumeAnyToken();
+ IsCommaFound = true;
+ } else if (Tok.isNot(tok::colon) &&
+ Tok.isNot(tok::annot_pragma_openmp_end)) {
+ Diag(Tok.getLocation(), diag::err_expected) << "','";
+ IsCorrect = false;
+ }
+ }
+
+ if (IsCommaFound) {
+ Diag(Tok.getLocation(), diag::err_expected_type);
+ IsCorrect = false;
+ if (Tok.is(tok::annot_pragma_openmp_end))
+ return DeclGroupPtrTy();
+ }
+
+ if (ReductionTypes.empty()) {
+ SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+ return DeclGroupPtrTy();
+ }
+
+ if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))
+ return DeclGroupPtrTy();
+
+ // Consume ':'.
+ if (Tok.is(tok::colon))
+ ConsumeAnyToken();
+ else {
+ Diag(Tok.getLocation(), diag::err_expected) << "':'";
+ IsCorrect = false;
+ }
+
+ if (Tok.is(tok::annot_pragma_openmp_end)) {
+ Diag(Tok.getLocation(), diag::err_expected_expression);
+ return DeclGroupPtrTy();
+ }
+
+ DeclGroupPtrTy DRD = Actions.ActOnOpenMPDeclareReductionDirectiveStart(
+ getCurScope(), Actions.getCurLexicalContext(), Name, ReductionTypes, AS);
+
+ // Parse <combiner> expression and then parse initializer if any for each
+ // correct type.
+ unsigned i = 0, e = ReductionTypes.size();
+ for (auto *D : DRD.get()) {
+ TentativeParsingAction TPA(*this);
+ ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |
+ Scope::OpenMPDirectiveScope);
+ // Parse <combiner> expression.
+ Actions.ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D);
+ ExprResult CombinerResult =
+ Actions.ActOnFinishFullExpr(ParseAssignmentExpression().get(),
+ D->getLocation(), /*DiscardedValue=*/true);
+ Actions.ActOnOpenMPDeclareReductionCombinerEnd(D, CombinerResult.get());
+
+ if (CombinerResult.isInvalid() && Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end)) {
+ TPA.Commit();
+ IsCorrect = false;
+ break;
+ }
+ IsCorrect = !T.consumeClose() && IsCorrect && !CombinerResult.isInvalid();
+ ExprResult InitializerResult;
+ if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ // Parse <initializer> expression.
+ if (Tok.isAnyIdentifier() &&
+ Tok.getIdentifierInfo()->isStr("initializer")) {
+ ConsumeToken();
+ } else {
+ Diag(Tok.getLocation(), diag::err_expected) << "'initializer'";
+ TPA.Commit();
+ IsCorrect = false;
+ break;
+ }
+ // Parse '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren,
+ tok::annot_pragma_openmp_end);
+ IsCorrect =
+ !T.expectAndConsume(diag::err_expected_lparen_after, "initializer") &&
+ IsCorrect;
+ if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |
+ Scope::OpenMPDirectiveScope);
+ // Parse expression.
+ Actions.ActOnOpenMPDeclareReductionInitializerStart(getCurScope(), D);
+ InitializerResult = Actions.ActOnFinishFullExpr(
+ ParseAssignmentExpression().get(), D->getLocation(),
+ /*DiscardedValue=*/true);
+ Actions.ActOnOpenMPDeclareReductionInitializerEnd(
+ D, InitializerResult.get());
+ if (InitializerResult.isInvalid() && Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end)) {
+ TPA.Commit();
+ IsCorrect = false;
+ break;
+ }
+ IsCorrect =
+ !T.consumeClose() && IsCorrect && !InitializerResult.isInvalid();
+ }
+ }
+
+ CombinersInitializers.push_back(
+ std::make_pair(CombinerResult.get(), InitializerResult.get()));
+ ++i;
+ // Revert parsing if not the last type, otherwise accept it, we're done with
+ // parsing.
+ if (i != e)
+ TPA.Revert();
+ else
+ TPA.Commit();
+ }
+ return Actions.ActOnOpenMPDeclareReductionDirectiveEnd(getCurScope(), DRD);
+}
+
/// \brief Parsing of declarative OpenMP directives.
///
/// threadprivate-directive:
/// annot_pragma_openmp 'threadprivate' simple-variable-list
+/// annot_pragma_openmp_end
+///
+/// declare-reduction-directive:
+/// annot_pragma_openmp 'declare' 'reduction' [...]
+/// annot_pragma_openmp_end
///
-Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
+Parser::DeclGroupPtrTy
+Parser::ParseOpenMPDeclarativeDirective(AccessSpecifier AS) {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -109,6 +361,21 @@
return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers);
}
break;
+ case OMPD_declare_reduction:
+ ConsumeToken();
+ if (auto Res = ParseOpenMPDeclareReductionDirective(AS)) {
+ // 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_reduction);
+ SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+ }
+ // Skip the last annot_pragma_openmp_end.
+ ConsumeToken();
+ return Res;
+ }
+ break;
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
break;
@@ -151,6 +418,12 @@
/// annot_pragma_openmp 'threadprivate' simple-variable-list
/// annot_pragma_openmp_end
///
+/// declare-reduction-directive:
+/// annot_pragma_openmp 'declare' 'reduction' '(' <reduction_id> ':'
+/// <type> {',' <type>} ':' <expression> ')' ['initializer' '('
+/// ('omp_priv' '=' <expression>|<function_call>) ')']
+/// annot_pragma_openmp_end
+///
/// executable-directive:
/// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |
/// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] |
@@ -196,6 +469,20 @@
}
SkipUntil(tok::annot_pragma_openmp_end);
break;
+ case OMPD_declare_reduction:
+ ConsumeToken();
+ if (auto Res = ParseOpenMPDeclareReductionDirective(/*AS=*/AS_none)) {
+ // 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_reduction);
+ SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
+ }
+ Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
+ }
+ SkipUntil(tok::annot_pragma_openmp_end);
+ break;
case OMPD_flush:
if (PP.LookAhead(0).is(tok::l_paren)) {
FlushHasClause = true;
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp
+++ lib/Parse/ParseDeclCXX.cpp
@@ -3008,7 +3008,7 @@
}
if (Tok.is(tok::annot_pragma_openmp)) {
- ParseOpenMPDeclarativeDirective();
+ ParseOpenMPDeclarativeDirective(CurAS);
continue;
}
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp
+++ lib/Parse/ParseDecl.cpp
@@ -3615,6 +3615,11 @@
continue;
}
+ if (Tok.is(tok::annot_pragma_openmp)) {
+ ParseOpenMPDeclarativeDirective(AS_public);
+ continue;
+ }
+
if (!Tok.is(tok::at)) {
auto CFieldCallback = [&](ParsingFieldDeclarator &FD) {
// Install the declarator into the current TagDecl.
Index: lib/CodeGen/CGDecl.cpp
===================================================================
--- lib/CodeGen/CGDecl.cpp
+++ lib/CodeGen/CGDecl.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclOpenMP.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CGFunctionInfo.h"
@@ -113,6 +114,9 @@
return EmitVarDecl(VD);
}
+ case Decl::OMPDeclareReduction:
+ return CGM.EmitOMPDeclareReduction(cast<OMPDeclareReductionDecl>(&D));
+
case Decl::Typedef: // typedef int X;
case Decl::TypeAlias: { // using X = int; [C++0x]
const TypedefNameDecl &TD = cast<TypedefNameDecl>(D);
@@ -1803,3 +1807,9 @@
if (D.hasAttr<AnnotateAttr>())
EmitVarAnnotations(&D, DeclPtr);
}
+
+void CodeGenModule::EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D) {
+ llvm_unreachable("Codegen for 'omp declare reduction' is not supported yet.");
+}
+
+
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -3386,6 +3386,10 @@
break;
}
+ case Decl::OMPDeclareReduction:
+ EmitOMPDeclareReduction(cast<OMPDeclareReductionDecl>(D));
+ break;
+
default:
// Make sure we handled everything we should, every other kind is a
// non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -20,6 +20,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/Mangle.h"
#include "clang/Basic/ABI.h"
@@ -1125,6 +1126,10 @@
/// \param D Threadprivate declaration.
void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D);
+ /// \brief Emit a code for declare reduction construct.
+ ///
+ void EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D);
+
/// Returns whether the given record is blacklisted from control flow
/// integrity checks.
bool IsCFIBlacklistedRecord(const CXXRecordDecl *RD);
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -8311,7 +8311,7 @@
// We never need to emit an uninstantiated function template.
if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
return false;
- } else if (isa<OMPThreadPrivateDecl>(D))
+ } else if (isa<OMPThreadPrivateDecl>(D) || isa<OMPDeclareReductionDecl>(D))
return true;
else
return false;
Index: lib/AST/DeclBase.cpp
===================================================================
--- lib/AST/DeclBase.cpp
+++ lib/AST/DeclBase.cpp
@@ -613,6 +613,9 @@
case TemplateTemplateParm:
return IDNS_Ordinary | IDNS_Tag | IDNS_Type;
+ case OMPDeclareReduction:
+ return IDNS_OMPReduction;
+
// Never have names.
case Friend:
case FriendTemplate:
@@ -939,6 +942,7 @@
case Decl::LinkageSpec:
case Decl::Block:
case Decl::Captured:
+ case Decl::OMPDeclareReduction:
// There is only one DeclContext for these entities.
return this;
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
@@ -68,6 +69,8 @@
const DeclContext *DC = D->getDeclContext();
if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC))
return getEffectiveDeclContext(CD);
+ if (auto *DR = dyn_cast<OMPDeclareReductionDecl>(DC))
+ return getEffectiveDeclContext(DR);
if (const auto *VD = dyn_cast<VarDecl>(D))
if (VD->isExternC())
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
@@ -59,6 +60,8 @@
const DeclContext *DC = D->getDeclContext();
if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC))
return getEffectiveDeclContext(CD);
+ if (auto *DR = dyn_cast<OMPDeclareReductionDecl>(DC))
+ return getEffectiveDeclContext(DR);
return DC;
}
Index: lib/AST/DeclOpenMP.cpp
===================================================================
--- lib/AST/DeclOpenMP.cpp
+++ lib/AST/DeclOpenMP.cpp
@@ -52,3 +52,27 @@
std::copy(VL.begin(), VL.end(), Vars);
}
+//===----------------------------------------------------------------------===//
+// OMPDeclareReductionDecl Implementation.
+//===----------------------------------------------------------------------===//
+
+void OMPDeclareReductionDecl::anchor() {}
+
+OMPDeclareReductionDecl *OMPDeclareReductionDecl::Create(ASTContext &C,
+ DeclContext *DC,
+ SourceLocation L,
+ DeclarationName Name,
+ QualType T) {
+ OMPDeclareReductionDecl *D =
+ new (C, DC) OMPDeclareReductionDecl(OMPDeclareReduction, DC, L, Name, T);
+ return D;
+}
+
+OMPDeclareReductionDecl *
+OMPDeclareReductionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ OMPDeclareReductionDecl *D = new (C, ID)
+ OMPDeclareReductionDecl(OMPDeclareReduction, /*DC=*/nullptr,
+ SourceLocation(), DeclarationName(), QualType());
+ return D;
+}
+
Index: lib/AST/DeclPrinter.cpp
===================================================================
--- lib/AST/DeclPrinter.cpp
+++ lib/AST/DeclPrinter.cpp
@@ -92,6 +92,7 @@
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
+ void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
void PrintTemplateParameters(const TemplateParameterList *Params,
const TemplateArgumentList *Args = nullptr);
@@ -304,7 +305,7 @@
// FIXME: Need to be able to tell the DeclPrinter when
const char *Terminator = nullptr;
- if (isa<OMPThreadPrivateDecl>(*D))
+ if (isa<OMPThreadPrivateDecl>(*D) || isa<OMPDeclareReductionDecl>(*D))
Terminator = nullptr;
else if (isa<FunctionDecl>(*D) &&
cast<FunctionDecl>(*D)->isThisDeclarationADefinition())
@@ -1320,3 +1321,20 @@
}
}
+void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
+ if (!D->isInvalidDecl()) {
+ Out << "#pragma omp declare reduction (";
+ D->printName(Out);
+ Out << " : ";
+ D->getType().print(Out, Policy);
+ Out << " : ";
+ D->getCombiner()->printPretty(Out, 0, Policy, 0);
+ Out << ")";
+ if (auto *Init = D->getInitializer()) {
+ Out << " initializer(";
+ Init->printPretty(Out, 0, Policy, 0);
+ Out << ")";
+ }
+ }
+}
+
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
@@ -1459,6 +1460,10 @@
if (OldK == NewK)
return true;
+ // Declare reduction are always replaceable.
+ if (OMPDeclareReductionDecl::classofKind(NewK))
+ return false;
+
// A compatibility alias for a class can be replaced by an interface.
if (ObjCCompatibleAliasDecl::classofKind(OldK) &&
ObjCInterfaceDecl::classofKind(NewK))
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -2784,6 +2784,11 @@
if (isa<EnumDecl>(D))
return nullptr;
+ // Local declare reduction constructs referenced prior to definition may
+ // require instantiation.
+ if (isa<OMPDeclareReductionDecl>(D))
+ return nullptr;
+
// If we didn't find the decl, then we either have a sema bug, or we have a
// forward reference to a label declaration. Return null to indicate that
// we have an uninstantiated label.
Index: lib/Sema/ScopeInfo.cpp
===================================================================
--- lib/Sema/ScopeInfo.cpp
+++ lib/Sema/ScopeInfo.cpp
@@ -28,6 +28,7 @@
HasBranchIntoScope = false;
HasIndirectGoto = false;
HasDroppedStmt = false;
+ HasOMPDeclareReductionCombiner = false;
ObjCShouldCallSuper = false;
ObjCIsDesignatedInit = false;
ObjCWarnForNoDesignatedInitChain = false;
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -367,6 +367,19 @@
DeduceReturnType(FD, Loc))
return true;
}
+
+ // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
+ // Only the variables omp_in and omp_out are allowed in the combiner.
+ // Only the variables omp_priv and omp_orig are allowed in the
+ // initializer-clause.
+ auto *DRD = dyn_cast<OMPDeclareReductionDecl>(CurContext);
+ if (LangOpts.OpenMP && DRD && !CurContext->containsDecl(D) &&
+ isa<VarDecl>(D)) {
+ Diag(Loc, diag::err_omp_wrong_var_in_declare_reduction)
+ << getCurFunction()->HasOMPDeclareReductionCombiner;
+ Diag(D->getLocation(), diag::note_entity_declared_at) << D;
+ return true;
+ }
DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass,
ObjCPropertyAccess);
@@ -2860,6 +2873,9 @@
case Decl::ObjCIvar:
llvm_unreachable("forming non-member reference to ivar?");
+ case Decl::OMPDeclareReduction:
+ llvm_unreachable("forming a reference to OpenMP declare reduction");
+
// Enum constants are always r-values and never references.
// Unresolved using declarations are dependent.
case Decl::EnumConstant:
Index: lib/Sema/SemaLookup.cpp
===================================================================
--- lib/Sema/SemaLookup.cpp
+++ lib/Sema/SemaLookup.cpp
@@ -279,6 +279,10 @@
IDNS = Decl::IDNS_ObjCProtocol;
break;
+ case Sema::LookupOMPReductionName:
+ IDNS = Decl::IDNS_OMPReduction;
+ break;
+
case Sema::LookupAnyName:
IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member
| Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol
@@ -1838,6 +1842,7 @@
case LookupNamespaceName:
case LookupObjCProtocolName:
case LookupLabel:
+ case LookupOMPReductionName:
// These lookups will never find a member in a C++ class (or base class).
return false;
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -5494,7 +5494,7 @@
static bool shouldConsiderLinkage(const VarDecl *VD) {
const DeclContext *DC = VD->getDeclContext()->getRedeclContext();
- if (DC->isFunctionOrMethod())
+ if (DC->isFunctionOrMethod() || isa<OMPDeclareReductionDecl>(DC))
return VD->hasExternalStorage();
if (DC->isFileContext())
return true;
@@ -5505,7 +5505,8 @@
static bool shouldConsiderLinkage(const FunctionDecl *FD) {
const DeclContext *DC = FD->getDeclContext()->getRedeclContext();
- if (DC->isFileContext() || DC->isFunctionOrMethod())
+ if (DC->isFileContext() || DC->isFunctionOrMethod() ||
+ isa<OMPDeclareReductionDecl>(DC))
return true;
if (DC->isRecord())
return false;
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2452,6 +2452,70 @@
return TD;
}
+Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
+ OMPDeclareReductionDecl *D) {
+ if (auto PrevInst = SemaRef.CurrentInstantiationScope->findInstantiationOf(D))
+ return PrevInst->get<Decl *>();
+ // Instantiate type and check if it is allowed.
+ QualType SubstReductionType = SemaRef.SubstType(
+ D->getType(), TemplateArgs, D->getLocation(), DeclarationName());
+ bool IsCorrect = !SubstReductionType.isNull() &&
+ SemaRef.isOpenMPDeclareReductionTypeAllowed(
+ D->getLocation(), SubstReductionType, llvm::None);
+ // Create instantiated copy.
+ std::pair<QualType, SourceLocation> ReductionTypes[] = {
+ std::make_pair(SubstReductionType, D->getLocation())};
+ Decl *NextDeclInScope = D->getNextDeclInScope();
+ if (NextDeclInScope) {
+ while (NextDeclInScope && NextDeclInScope->isInvalidDecl())
+ NextDeclInScope =
+ cast<OMPDeclareReductionDecl>(NextDeclInScope)->getNextDeclInScope();
+ if (NextDeclInScope)
+ NextDeclInScope = SemaRef.SubstDecl(NextDeclInScope, Owner, TemplateArgs);
+ }
+ auto DRD = SemaRef.ActOnOpenMPDeclareReductionDirectiveStart(
+ /*S=*/nullptr, Owner, D->getDeclName(), ReductionTypes, D->getAccess(),
+ NextDeclInScope);
+ auto *NewDRD = cast<OMPDeclareReductionDecl>(DRD.get().getSingleDecl());
+ if (isDeclWithinFunction(NewDRD))
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDRD);
+ Expr *SubstCombiner = nullptr;
+ Expr *SubstInitializer = nullptr;
+ // Combiners instantiation sequence.
+ if (D->getCombiner()) {
+ SemaRef.ActOnOpenMPDeclareReductionCombinerStart(
+ /*S=*/nullptr, NewDRD);
+ for (auto *Local : D->decls()) {
+ auto Lookup = NewDRD->lookup(cast<NamedDecl>(Local)->getDeclName());
+ if (!Lookup.empty()) {
+ assert(Lookup.size() == 1);
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(Local,
+ Lookup.front());
+ }
+ }
+ SubstCombiner = SemaRef.SubstExpr(D->getCombiner(), TemplateArgs).get();
+ SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner);
+ // Initializers instantiation sequence.
+ if (D->getInitializer()) {
+ SemaRef.ActOnOpenMPDeclareReductionInitializerStart(
+ /*S=*/nullptr, NewDRD);
+ SubstInitializer =
+ SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get();
+ IsCorrect = IsCorrect && SubstCombiner &&
+ (!D->getInitializer() || SubstInitializer);
+ SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(NewDRD,
+ SubstInitializer);
+ }
+ } else
+ IsCorrect = false;
+
+ if (!IsCorrect)
+ NewDRD->setInvalidDecl();
+ (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(/*S=*/nullptr, DRD);
+
+ return NewDRD;
+}
+
Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
return VisitFunctionDecl(D, nullptr);
}
Index: lib/Sema/SemaOpenMP.cpp
===================================================================
--- lib/Sema/SemaOpenMP.cpp
+++ lib/Sema/SemaOpenMP.cpp
@@ -1342,6 +1342,7 @@
case OMPD_cancellation_point:
case OMPD_cancel:
case OMPD_flush:
+ case OMPD_declare_reduction:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
@@ -2141,6 +2142,7 @@
EndLoc);
break;
case OMPD_threadprivate:
+ case OMPD_declare_reduction:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
@@ -6619,3 +6621,216 @@
return OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, DepKind,
DepLoc, ColonLoc, Vars);
}
+
+bool Sema::isOpenMPDeclareReductionTypeAllowed(
+ SourceLocation TyLoc, QualType ReductionType,
+ ArrayRef<std::pair<QualType, SourceLocation>> RegisteredReductionTypes) {
+ assert(!ReductionType.isNull());
+
+ // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions, C\C++
+ // A type name in a declare reduction directive cannot be a function type, an
+ // array type, a reference type, or a type qualified with const, volatile or
+ // restrict.
+ if (ReductionType.hasQualifiers()) {
+ Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 0;
+ return false;
+ }
+
+ if (ReductionType->isFunctionType()) {
+ Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 1;
+ return false;
+ }
+ if (ReductionType->isReferenceType()) {
+ Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 2;
+ return false;
+ }
+ if (ReductionType->isArrayType()) {
+ Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 3;
+ return false;
+ }
+
+ bool IsValid = true;
+ for (auto &&Data : RegisteredReductionTypes) {
+ if (Context.hasSameType(ReductionType, Data.first)) {
+ Diag(TyLoc, diag::err_omp_reduction_redeclared) << ReductionType;
+ Diag(Data.second, diag::note_previous_declaration) << Data.second;
+ IsValid = false;
+ break;
+ }
+ }
+ return IsValid;
+}
+
+Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart(
+ Scope *S, DeclContext *DC, DeclarationName Name,
+ ArrayRef<std::pair<QualType, SourceLocation>> ReductionTypes,
+ AccessSpecifier AS, Decl *NextDeclInScope) {
+ SmallVector<Decl *, 8> Decls;
+ Decls.reserve(ReductionTypes.size());
+
+ LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPReductionName);
+ Lookup.suppressDiagnostics();
+ // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
+ // A reduction-identifier may not be re-declared in the current scope for the
+ // same type or for a type that is compatible according to the base language
+ // rules.
+ if (S) {
+ LookupName(Lookup, S);
+ FilterLookupForScope(Lookup, DC, S, /*ConsiderLinkage=*/false,
+ /*AllowInlineNamespace=*/false);
+ } else
+ while (NextDeclInScope) {
+ auto *NextDRD = cast<OMPDeclareReductionDecl>(NextDeclInScope);
+ Lookup.addDecl(NextDRD);
+ NextDeclInScope = NextDRD->getNextDeclInScope();
+ }
+ OMPDeclareReductionDecl *PrevDeclInScope = nullptr;
+ for (auto &TyData : ReductionTypes) {
+ auto *DRD = OMPDeclareReductionDecl::Create(Context, DC, TyData.second,
+ Name, TyData.first);
+ DC->addDecl(DRD);
+ DRD->setAccess(AS);
+ Decls.push_back(DRD);
+ auto Filter = Lookup.makeFilter();
+ while (Filter.hasNext()) {
+ auto *PrevDecl = cast<OMPDeclareReductionDecl>(Filter.next());
+ if (!PrevDeclInScope && !PrevDecl->getNextDeclInScope())
+ PrevDeclInScope = PrevDecl;
+ if (PrevDecl->isInvalidDecl()) {
+ Filter.erase();
+ continue;
+ }
+ if (Context.typesAreCompatible(TyData.first, PrevDecl->getType(),
+ /*CompareUnqualified=*/true)) {
+ Diag(S ? TyData.second : PrevDecl->getLocation(),
+ diag::err_omp_declare_reduction_redefinition)
+ << (S ? TyData.first : PrevDecl->getType());
+ Diag(S ? PrevDecl->getLocation() : TyData.second,
+ diag::note_previous_definition);
+ DRD->setInvalidDecl();
+ }
+ }
+ Filter.done();
+ if (PrevDeclInScope)
+ PrevDeclInScope->setNextDeclInScope(DRD);
+ PrevDeclInScope = DRD;
+ }
+
+ return DeclGroupPtrTy::make(
+ DeclGroupRef::Create(Context, Decls.begin(), Decls.size()));
+}
+
+void Sema::ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D) {
+ auto *DRD = cast<OMPDeclareReductionDecl>(D);
+
+ // Enter new function scope.
+ PushFunctionScope();
+ getCurFunction()->setHasBranchProtectedScope();
+ getCurFunction()->setHasOMPDeclareReductionCombiner();
+
+ if (S)
+ PushDeclContext(S, DRD);
+ else
+ CurContext = DRD;
+
+ PushExpressionEvaluationContext(PotentiallyEvaluated);
+
+ QualType ReductionType = DRD->getType();
+ // Create 'T omp_in;' implicit param.
+ auto *OmpInParm =
+ ImplicitParamDecl::Create(Context, DRD, D->getLocation(),
+ &Context.Idents.get("omp_in"), ReductionType);
+ // Create 'T &omp_out;' implicit param.
+ auto *OmpOutParm = ImplicitParamDecl::Create(
+ Context, DRD, D->getLocation(), &Context.Idents.get("omp_out"),
+ Context.getLValueReferenceType(ReductionType));
+ if (S) {
+ PushOnScopeChains(OmpInParm, S);
+ PushOnScopeChains(OmpOutParm, S);
+ } else {
+ DRD->addDecl(OmpInParm);
+ DRD->addDecl(OmpOutParm);
+ }
+}
+
+void Sema::ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner) {
+ auto *DRD = cast<OMPDeclareReductionDecl>(D);
+ DiscardCleanupsInEvaluationContext();
+ PopExpressionEvaluationContext();
+
+ PopDeclContext();
+ PopFunctionScopeInfo();
+
+ if (Combiner)
+ DRD->setCombiner(Combiner);
+ else
+ DRD->setInvalidDecl();
+}
+
+void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) {
+ auto *DRD = cast<OMPDeclareReductionDecl>(D);
+
+ // Enter new function scope.
+ PushFunctionScope();
+ getCurFunction()->setHasBranchProtectedScope();
+
+ if (S)
+ PushDeclContext(S, DRD);
+ else
+ CurContext = DRD;
+
+ PushExpressionEvaluationContext(PotentiallyEvaluated);
+
+ QualType ReductionType = DRD->getType();
+ // Create 'T omp_orig;' implicit param.
+ auto *OmpOrigParm =
+ ImplicitParamDecl::Create(Context, DRD, D->getLocation(),
+ &Context.Idents.get("omp_orig"), ReductionType);
+ // Create 'T &omp_priv;' implicit param.
+ auto *OmpPrivParm = ImplicitParamDecl::Create(
+ Context, DRD, D->getLocation(), &Context.Idents.get("omp_priv"),
+ Context.getLValueReferenceType(ReductionType));
+ if (S) {
+ PushOnScopeChains(OmpPrivParm, S);
+ PushOnScopeChains(OmpOrigParm, S);
+ } else {
+ DRD->addDecl(OmpPrivParm);
+ DRD->addDecl(OmpOrigParm);
+ }
+}
+
+void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D,
+ Expr *Initializer) {
+ auto *DRD = cast<OMPDeclareReductionDecl>(D);
+ DiscardCleanupsInEvaluationContext();
+ PopExpressionEvaluationContext();
+
+ PopDeclContext();
+ PopFunctionScopeInfo();
+
+ if (Initializer)
+ DRD->setInitializer(Initializer);
+ else
+ DRD->setInvalidDecl();
+
+ if (Initializer)
+ DRD->setInitializer(Initializer);
+ else
+ DRD->setInvalidDecl();
+}
+
+Sema::DeclGroupPtrTy
+Sema::ActOnOpenMPDeclareReductionDirectiveEnd(Scope *S,
+ DeclGroupPtrTy DeclReductions) {
+ // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
+ // A reduction-identifier may not be re-declared in the current scope for the
+ // same type or for a type that is compatible according to the base language
+ // rules.
+ for (auto *D : DeclReductions.get()) {
+ auto *DRD = cast<OMPDeclareReductionDecl>(D);
+ if (S)
+ PushOnScopeChains(DRD, S, /*AddToContext=*/false);
+ }
+ return DeclReductions;
+}
+
Index: lib/Basic/OpenMPKinds.cpp
===================================================================
--- lib/Basic/OpenMPKinds.cpp
+++ lib/Basic/OpenMPKinds.cpp
@@ -360,6 +360,7 @@
case OMPD_cancellation_point:
case OMPD_cancel:
case OMPD_ordered:
+ case OMPD_declare_reduction:
break;
}
return false;
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -5066,6 +5066,7 @@
case Decl::ClassScopeFunctionSpecialization:
case Decl::Import:
case Decl::OMPThreadPrivate:
+ case Decl::OMPDeclareReduction:
case Decl::ObjCTypeParam:
return C;
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1112,6 +1112,8 @@
DECL_EMPTY,
/// \brief An ObjCTypeParamDecl record.
DECL_OBJC_TYPE_PARAM,
+ /// \brief An OMPDeclareReductionDecl record.
+ DECL_OMP_DECLARE_REDUCTION,
};
/// \brief Record codes for each kind of statement or expression.
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -2416,7 +2416,9 @@
//===--------------------------------------------------------------------===//
// OpenMP: Directives and clauses.
/// \brief Parses declarative OpenMP directives.
- DeclGroupPtrTy ParseOpenMPDeclarativeDirective();
+ DeclGroupPtrTy ParseOpenMPDeclarativeDirective(AccessSpecifier AS);
+ /// \brief Parse 'omp declare reduction' construct.
+ DeclGroupPtrTy ParseOpenMPDeclareReductionDirective(AccessSpecifier AS);
/// \brief Parses simple list of variables.
///
/// \param Kind Kind of the directive.
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -1463,6 +1463,14 @@
}
})
+DEF_TRAVERSE_DECL(OMPDeclareReductionDecl, {
+ TRY_TO(TraverseDeclaratorHelper(D));
+ TRY_TO(TraverseStmt(D->getCombiner()));
+ if (auto *Initializer = D->getInitializer())
+ TRY_TO(TraverseStmt(Initializer));
+ return true;
+})
+
// A helper method for TemplateDecl's children.
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
Index: include/clang/AST/DataRecursiveASTVisitor.h
===================================================================
--- include/clang/AST/DataRecursiveASTVisitor.h
+++ include/clang/AST/DataRecursiveASTVisitor.h
@@ -1389,6 +1389,13 @@
}
})
+DEF_TRAVERSE_DECL(OMPDeclareReductionDecl, {
+ TRY_TO(TraverseDeclaratorHelper(D));
+ if (auto *Initializer = D->getInitializer())
+ TRY_TO(TraverseStmt(Initializer));
+ return true;
+})
+
// A helper method for TemplateDecl's children.
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
Index: include/clang/AST/DeclOpenMP.h
===================================================================
--- include/clang/AST/DeclOpenMP.h
+++ include/clang/AST/DeclOpenMP.h
@@ -15,11 +15,12 @@
#ifndef LLVM_CLANG_AST_DECLOPENMP_H
#define LLVM_CLANG_AST_DECLOPENMP_H
-#include "clang/AST/DeclBase.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
#include "llvm/ADT/ArrayRef.h"
namespace clang {
-class Expr;
/// \brief This represents '#pragma omp threadprivate ...' directive.
/// For example, in the following, both 'a' and 'A::b' are threadprivate:
@@ -85,6 +86,82 @@
static bool classofKind(Kind K) { return K == OMPThreadPrivate; }
};
+/// \brief This represents '#pragma omp declare reduction ...' directive.
+/// For example, in the following, declared reduction 'foo' for types 'int' and
+/// 'float':
+///
+/// \code
+/// #pragma omp declare reduction (foo : int,float : omp_out += omp_in)
+/// initializer (omp_priv = 0)
+/// \endcode
+///
+/// Here 'omp_out += omp_in' is a combiner and 'omp_priv = 0' is an initializer.
+class OMPDeclareReductionDecl : public DeclaratorDecl, public DeclContext {
+private:
+ friend class ASTDeclReader;
+ /// \brief Combiner for declare reduction construct.
+ Stmt *Combiner;
+ /// \brief Initializer for declare reduction construct.
+ Stmt *Initializer;
+ /// \brief Reference to the previous declare reduction construct in the same
+ /// scope with the same name. Required for proper templates instantiation if
+ /// the declare reduction construct is declared inside compound statement.
+ Decl *NextDeclInScope;
+
+ virtual void anchor();
+
+ OMPDeclareReductionDecl(Kind DK, DeclContext *DC, SourceLocation L,
+ DeclarationName Name, QualType T)
+ : DeclaratorDecl(DK, DC, L, Name, T, nullptr, SourceLocation()),
+ DeclContext(DK), Combiner(nullptr), Initializer(nullptr),
+ NextDeclInScope(nullptr) {}
+
+public:
+ /// \brief Create declare reduction node.
+ /// \param PrevDeclInScope Previous declare reduction construct in the same
+ /// scope with the same but with different type.
+ static OMPDeclareReductionDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
+ QualType T);
+ static OMPDeclareReductionDecl *CreateDeserialized(ASTContext &C,
+ unsigned ID);
+
+ /// \brief Get combiner expression of the declare reduction construct.
+ Expr *getCombiner() { return cast<Expr>(Combiner); }
+ Expr *getCombiner() const { return cast<Expr>(Combiner); }
+ /// \brief Set combiner expression for the declare reduction construct.
+ void setCombiner(Expr *E) { Combiner = E; }
+
+ /// \brief Get initializer expression (if specified) of the declare reduction
+ /// construct.
+ Expr *getInitializer() { return cast_or_null<Expr>(Initializer); }
+ Expr *getInitializer() const { return cast_or_null<Expr>(Initializer); }
+ /// \brief Set initializer expression for the declare reduction construct.
+ void setInitializer(Expr *E) { Initializer = E; }
+
+ /// \brief Get reference to previous declare reduction construct in the same
+ /// scope with the same name.
+ OMPDeclareReductionDecl *getNextDeclInScope() {
+ return cast_or_null<OMPDeclareReductionDecl>(NextDeclInScope);
+ }
+ OMPDeclareReductionDecl *getNextDeclInScope() const {
+ return cast_or_null<OMPDeclareReductionDecl>(NextDeclInScope);
+ }
+ /// \brief Set reference to previous declare reduction construct in the same
+ /// scope with the same name.
+ void setNextDeclInScope(OMPDeclareReductionDecl *D) { NextDeclInScope = D; }
+
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == OMPDeclareReduction; }
+ static DeclContext *castToDeclContext(const OMPDeclareReductionDecl *D) {
+ return static_cast<DeclContext *>(const_cast<OMPDeclareReductionDecl *>(D));
+ }
+ static OMPDeclareReductionDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<OMPDeclareReductionDecl *>(
+ const_cast<DeclContext *>(DC));
+ }
+};
+
} // end namespace clang
#endif
Index: include/clang/AST/DeclBase.h
===================================================================
--- include/clang/AST/DeclBase.h
+++ include/clang/AST/DeclBase.h
@@ -161,7 +161,10 @@
/// This declaration is a function-local extern declaration of a
/// variable or function. This may also be IDNS_Ordinary if it
/// has been declared outside any function.
- IDNS_LocalExtern = 0x0800
+ IDNS_LocalExtern = 0x0800,
+
+ /// This declaration is an OpenMP user defined reduction construction.
+ IDNS_OMPReduction = 0x1000
};
/// ObjCDeclQualifier - 'Qualifiers' written next to the return and
@@ -251,7 +254,7 @@
SourceLocation Loc;
/// DeclKind - This indicates which class this is.
- unsigned DeclKind : 8;
+ unsigned DeclKind : 7;
/// InvalidDecl - This indicates a semantic error occurred.
unsigned InvalidDecl : 1;
@@ -291,7 +294,7 @@
unsigned Hidden : 1;
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
- unsigned IdentifierNamespace : 12;
+ unsigned IdentifierNamespace : 13;
/// \brief If 0, we have not computed the linkage of this declaration.
/// Otherwise, it is the linkage + 1.
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 OMPDeclareReductionDecl;
class OMPClause;
class OverloadCandidateSet;
class OverloadExpr;
@@ -2631,6 +2632,8 @@
LookupObjCProtocolName,
/// Look up implicit 'self' parameter of an objective-c method.
LookupObjCImplicitSelfParam,
+ /// \brief Look up the name of an OpenMP user-defined reduction operation.
+ LookupOMPReductionName,
/// \brief Look up any declaration with any name.
LookupAnyName
};
@@ -7708,6 +7711,12 @@
/// is performed.
bool isOpenMPPrivateVar(VarDecl *VD, unsigned Level);
+ /// \brief Check if the specified type is allowed to be used in 'omp declare
+ /// reduction' construct.
+ bool isOpenMPDeclareReductionTypeAllowed(
+ SourceLocation TyLoc, QualType ReductionType,
+ ArrayRef<std::pair<QualType, SourceLocation>> RegisteredReductionTypes);
+
ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc,
Expr *Op);
/// \brief Called on start of new data sharing attribute block.
@@ -7741,6 +7750,23 @@
OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl(
SourceLocation Loc,
ArrayRef<Expr *> VarList);
+ /// \brief Called on start of '#pragma omp declare reduction'.
+ DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveStart(
+ Scope *S, DeclContext *DC, DeclarationName Name,
+ ArrayRef<std::pair<QualType, SourceLocation>> ReductionTypes,
+ AccessSpecifier AS, Decl *NextDeclInScope = nullptr);
+ /// \brief Initialize declare reduction construct initializer.
+ void ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D);
+ /// \brief Finish current declare reduction construct initializer.
+ void ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner);
+ /// \brief Initialize declare reduction construct initializer.
+ void ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D);
+ /// \brief Finish current declare reduction construct initializer.
+ void ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer);
+ /// \brief Called on well-formed '#pragma omp declare reduction'.
+ DeclGroupPtrTy
+ ActOnOpenMPDeclareReductionDirectiveEnd(Scope *S,
+ DeclGroupPtrTy DeclReductions);
/// \brief Initialization of captured region for OpenMP region.
void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope);
Index: include/clang/Sema/ScopeInfo.h
===================================================================
--- include/clang/Sema/ScopeInfo.h
+++ include/clang/Sema/ScopeInfo.h
@@ -104,6 +104,9 @@
/// \brief Whether a statement was dropped because it was invalid.
bool HasDroppedStmt;
+ /// \brief True if current scope is for OpenMP declare reduction combiner.
+ bool HasOMPDeclareReductionCombiner;
+
/// A flag that is set when parsing a method that must call super's
/// implementation, such as \c -dealloc, \c -finalize, or any method marked
/// with \c __attribute__((objc_requires_super)).
@@ -327,6 +330,10 @@
HasDroppedStmt = true;
}
+ void setHasOMPDeclareReductionCombiner() {
+ HasOMPDeclareReductionCombiner = true;
+ }
+
void setHasCXXTry(SourceLocation TryLoc) {
setHasBranchProtectedScope();
FirstCXXTryLoc = TryLoc;
@@ -349,6 +356,7 @@
HasBranchIntoScope(false),
HasIndirectGoto(false),
HasDroppedStmt(false),
+ HasOMPDeclareReductionCombiner(false),
ObjCShouldCallSuper(false),
ObjCIsDesignatedInit(false),
ObjCWarnForNoDesignatedInitChain(false),
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7661,6 +7661,10 @@
"parent region for 'omp %select{cancellation point/cancel}0' construct cannot be \
nowait">; def err_omp_parent_cancel_region_ordered : Error<
"parent region for 'omp %select{cancellation point/cancel}0' construct cannot be \
ordered">; +def err_omp_reduction_wrong_type : Error<"reduction type cannot be \
%select{qualified with 'const', 'volatile' or 'restrict'|a function|a reference|an \
array}0 type">; +def err_omp_reduction_redeclared : Error<"previous declaration with \
type %0 is found">; +def err_omp_wrong_var_in_declare_reduction : Error<"only \
%select{'omp_priv' or 'omp_orig'|'omp_in' or 'omp_out'}0 variables are allowed in \
%select{initializer|combiner}0 expression">; +def \
err_omp_declare_reduction_redefinition : Error<"redefinition of user-defined \
reduction for type %0">; } // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -989,6 +989,8 @@
"'#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_expected_reduction_identifier : Error<
+ "expected identifier or one of the following operators: '+', '-', '*', '&', '|', \
'^', '&&' and '||'">;
// Pragma loop support.
def err_pragma_loop_missing_argument : Error<
Index: include/clang/Basic/DeclNodes.td
===================================================================
--- include/clang/Basic/DeclNodes.td
+++ include/clang/Basic/DeclNodes.td
@@ -52,6 +52,7 @@
def ImplicitParam : DDecl<Var>;
def ParmVar : DDecl<Var>;
def NonTypeTemplateParm : DDecl<Declarator>;
+ def OMPDeclareReduction : DDecl<Declarator>, DeclContext;
def Template : DDecl<Named, 1>;
def RedeclarableTemplate : DDecl<Template, 1>;
def FunctionTemplate : DDecl<RedeclarableTemplate>;
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_reduction, "declare reduction")
// OpenMP clauses.
OPENMP_CLAUSE(if, OMPIfClause)
Index: test/OpenMP/declare_reduction_ast_print.cpp
===================================================================
--- test/OpenMP/declare_reduction_ast_print.cpp
+++ test/OpenMP/declare_reduction_ast_print.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s \
-ast-print | FileCheck %s +// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+
+#pragma omp declare reduction(+ : int, char : omp_out *= omp_in)
+// CHECK: #pragma omp declare reduction (+ : int : omp_out *= omp_in)
+// CHECK-NEXT: #pragma omp declare reduction (+ : char : omp_out *= omp_in)
+
+// CHECK: #pragma omp declare reduction (fun : int : omp_out += omp_in) \
initializer(omp_priv = omp_orig + 15) +
+template <class T>
+class SSS {
+public:
+#pragma omp declare reduction(fun : T : omp_out += omp_in) initializer(omp_priv = \
omp_orig + 15) + // CHECK: #pragma omp declare reduction (fun : T : omp_out += \
omp_in) initializer(omp_priv = omp_orig + 15) +};
+
+SSS<int> d;
+
+void init(SSS<int> &lhs, SSS<int> rhs);
+
+#pragma omp declare reduction(fun : SSS < int > : omp_out = omp_in) \
initializer(init(omp_priv, omp_orig)) +// CHECK: #pragma omp declare reduction (fun : \
SSS<int> : omp_out = omp_in) initializer(init(omp_priv, omp_orig)) +
+// CHECK: template <typename T = int> int foo(int a) {
+// CHECK: #pragma omp declare reduction (fun : int : omp_out += omp_in) \
initializer(omp_priv = omp_orig + 15); +// CHECK: {
+// CHECK: #pragma omp declare reduction (fun : int : omp_out += omp_in) \
initializer(omp_priv = omp_orig + 15); +// CHECK: }
+// CHECK: return a;
+// CHECK: }
+
+// CHECK: template <typename T> T foo(T a) {
+// CHECK: #pragma omp declare reduction (fun : T : omp_out += omp_in) \
initializer(omp_priv = omp_orig + 15); +// CHECK: {
+// CHECK: #pragma omp declare reduction (fun : T : omp_out += omp_in) \
initializer(omp_priv = omp_orig + 15); +// CHECK: }
+// CHECK: return a;
+// CHECK: }
+template <typename T>
+T foo(T a) {
+#pragma omp declare reduction(fun : T : omp_out += omp_in) initializer(omp_priv = \
omp_orig + 15) + {
+#pragma omp declare reduction(fun : T : omp_out += omp_in) initializer(omp_priv = \
omp_orig + 15) + }
+ return a;
+}
+
+int main() {
+ int i = 0;
+ SSS<int> sss;
+ // TODO: Add support for scoped reduction identifiers
+ // #pragma omp parallel reduction(SSS<int>::fun : i)
+ // TODO-CHECK: #pragma omp parallel reduction(SSS<int>::fun: i)
+ {
+ i += 1;
+ }
+ // #pragma omp parallel reduction(::fun:sss)
+ // TODO-CHECK: #pragma omp parallel reduction(::fun: sss)
+ {
+ }
+ return foo(15);
+}
+
+#endif
Index: test/OpenMP/declare_reduction_messages.c
===================================================================
--- test/OpenMP/declare_reduction_messages.c
+++ test/OpenMP/declare_reduction_messages.c
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+int temp; // expected-note 6 {{'temp' declared here}}
+
+#pragma omp declare reduction // \
expected-error {{expected '(' after 'declare reduction'}} +#pragma omp declare \
reduction { // expected-error {{expected \
'(' after 'declare reduction'}} +#pragma omp declare reduction( \
// expected-error {{expected identifier or one of the following operators: '+', '-', \
'*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction(# \
// expected-error {{expected identifier or one of the following operators: '+', '-', \
'*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction(/ \
// expected-error {{expected identifier or one of the following operators: '+', '-', \
'*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction(+ \
// expected-error {{expected ':'}} +#pragma omp declare reduction(for \
// expected-error {{expected identifier or one of the following operators: '+', '-', \
'*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction(if: \
// expected-error {{expected identifier or one of the following operators: '+', '-', \
'*', '&', '|', '^', '&&' and '||'}} expected-error {{expected a type}} +#pragma omp \
declare reduction(oper: // expected-error \
{{expected a type}} +#pragma omp declare reduction(oper; \
// expected-error {{expected ':'}} expected-error {{expected a type}} +#pragma omp \
declare reduction(fun : int // expected-error \
{{expected ':'}} expected-error {{expected expression}} +#pragma omp declare \
reduction(+ : const int: // expected-error {{reduction \
type cannot be qualified with 'const', 'volatile' or 'restrict'}} +#pragma omp \
declare reduction(- : volatile int: // expected-error \
{{reduction type cannot be qualified with 'const', 'volatile' or 'restrict'}} \
+#pragma omp declare reduction(* : int; // \
expected-error {{expected ','}} expected-error {{expected a type}} +#pragma omp \
declare reduction(& : double char: // expected-error \
{{cannot combine with previous 'double' declaration specifier}} expected-error \
{{expected expression}} +#pragma omp declare reduction(^ : double, char, : \
// expected-error {{expected a type}} expected-error {{expected expression}} +#pragma \
omp declare reduction(&& : int, S: // expected-error \
{{unknown type name 'S'}} expected-error {{expected expression}} +#pragma omp declare \
reduction(|| : int, double : temp += omp_in) // expected-error 2 {{only \
'omp_in' or 'omp_out' variables are allowed in combiner expression}} +#pragma omp \
declare reduction(| : char, float : omp_out += temp) // expected-error 2 \
{{only 'omp_in' or 'omp_out' variables are allowed in combiner expression}} +#pragma \
omp declare reduction(fun : long : omp_out += omp_in) { // expected-error \
{{expected 'initializer'}} expected-warning {{extra tokens at the end of '#pragma omp \
declare reduction' are ignored}} +#pragma omp declare reduction(fun : unsigned : \
omp_out += temp)) // expected-error {{expected 'initializer'}} \
expected-warning {{extra tokens at the end of '#pragma omp declare reduction' are \
ignored}} expected-error {{only 'omp_in' or 'omp_out' variables are allowed in \
combiner expression}} +#pragma omp declare reduction(fun : long(void) : omp_out += \
omp_in) // expected-error {{reduction type cannot be a function type}} \
+#pragma omp declare reduction(fun : long[3] : omp_out += omp_in) // \
expected-error {{reduction type cannot be an array type}} +#pragma omp declare \
reduction(fun23 : long, int, long : omp_out += omp_in) // expected-error {{previous \
declaration with type 'long' is found}} expected-note {{previous declaration is \
here}} +
+#pragma omp declare reduction(fun222 : long : omp_out += omp_in)
+#pragma omp declare reduction(fun1 : long : omp_out += omp_in) initializer \
// expected-error {{expected '(' after 'initializer'}} +#pragma omp declare \
reduction(fun2 : long : omp_out += omp_in) initializer { // \
expected-error {{expected '(' after 'initializer'}} expected-error {{expected \
expression}} expected-warning {{extra tokens at the end of '#pragma omp declare \
reduction' are ignored}} +#pragma omp declare reduction(fun3 : long : omp_out += \
omp_in) initializer[ // expected-error {{expected '(' after \
'initializer'}} expected-error {{expected expression}} expected-warning {{extra \
tokens at the end of '#pragma omp declare reduction' are ignored}} +#pragma omp \
declare reduction(fun4 : long : omp_out += omp_in) initializer() // \
expected-error {{expected expression}} +#pragma omp declare reduction(fun5 : long : \
omp_out += omp_in) initializer(temp) // expected-error {{only 'omp_priv' or \
'omp_orig' variables are allowed in initializer expression}} +#pragma omp declare \
reduction(fun6 : long : omp_out += omp_in) initializer(omp_orig // \
expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp \
declare reduction(fun7 : long : omp_out += omp_in) initializer(omp_priv 12) // \
expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp \
declare reduction(fun8 : long : omp_out += omp_in) initializer(omp_priv = 23) // \
expected-note {{previous definition is here}} +#pragma omp declare reduction(fun8 : \
long : omp_out += omp_in) initializer(omp_priv = 23)) // expected-warning {{extra \
tokens at the end of '#pragma omp declare reduction' are ignored}} expected-error \
{{redefinition of user-defined reduction for type 'long'}} +#pragma omp declare \
reduction(fun9 : long : omp_out += omp_in) initializer(omp_priv = ) // \
expected-error {{expected expression}} +
+int fun(int arg) {
+#pragma omp declare reduction(red : int : omp_out++)
+ {
+#pragma omp declare reduction(red : int : omp_out++) // expected-note {{previous \
definition is here}} +#pragma omp declare reduction(red : int : omp_out++) // \
expected-error {{redefinition of user-defined reduction for type 'int'}} + {
+#pragma omp declare reduction(red : int : omp_out++)
+ }
+ }
+ return arg;
+}
Index: test/OpenMP/declare_reduction_messages.cpp
===================================================================
--- test/OpenMP/declare_reduction_messages.cpp
+++ test/OpenMP/declare_reduction_messages.cpp
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
+
+int temp; // expected-note 7 {{'temp' declared here}}
+
+#pragma omp declare reduction // \
expected-error {{expected '(' after 'declare reduction'}} +#pragma omp declare \
reduction { // expected-error {{expected \
'(' after 'declare reduction'}} +#pragma omp declare reduction( \
// expected-error {{expected identifier or one of the following operators: '+', '-', \
'*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction(# \
// expected-error {{expected identifier or one of the following operators: '+', '-', \
'*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction(/ \
// expected-error {{expected identifier or one of the following operators: '+', '-', \
'*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction(+ \
// expected-error {{expected ':'}} +#pragma omp declare reduction(operator \
// expected-error {{expected identifier or one of the following operators: '+', '-', \
'*', '&', '|', '^', '&&' and '||'}} +#pragma omp declare reduction(operator: \
// expected-error {{expected identifier or one of the following operators: '+', '-', \
'*', '&', '|', '^', '&&' and '||'}} expected-error {{expected a type}} +#pragma omp \
declare reduction(oper: // expected-error \
{{expected a type}} +#pragma omp declare reduction(oper; \
// expected-error {{expected ':'}} expected-error {{expected a type}} +#pragma omp \
declare reduction(fun : int // expected-error \
{{expected ':'}} expected-error {{expected expression}} +#pragma omp declare \
reduction(+ : const int: // expected-error {{reduction \
type cannot be qualified with 'const', 'volatile' or 'restrict'}} +#pragma omp \
declare reduction(- : volatile int: // expected-error \
{{reduction type cannot be qualified with 'const', 'volatile' or 'restrict'}} \
+#pragma omp declare reduction(* : int; // \
expected-error {{expected ','}} expected-error {{expected a type}} +#pragma omp \
declare reduction(& : double char: // expected-error \
{{cannot combine with previous 'double' declaration specifier}} expected-error \
{{expected expression}} +#pragma omp declare reduction(^ : double, char, : \
// expected-error {{expected a type}} expected-error {{expected expression}} +#pragma \
omp declare reduction(&& : int, S: // expected-error \
{{unknown type name 'S'}} expected-error {{expected expression}} +#pragma omp declare \
reduction(|| : int, double : temp += omp_in) // expected-error 2 {{only \
'omp_in' or 'omp_out' variables are allowed in combiner expression}} +#pragma omp \
declare reduction(| : char, float : omp_out += ::temp) // expected-error 2 \
{{only 'omp_in' or 'omp_out' variables are allowed in combiner expression}} +#pragma \
omp declare reduction(fun : long : omp_out += omp_in) { // \
expected-warning {{extra tokens at the end of '#pragma omp declare reduction' are \
ignored}} expected-error {{expected 'initializer'}} +#pragma omp declare \
reduction(fun : unsigned : omp_out += ::temp)) // expected-warning {{extra \
tokens at the end of '#pragma omp declare reduction' are ignored}} expected-error \
{{expected 'initializer'}} expected-error {{only 'omp_in' or 'omp_out' variables are \
allowed in combiner expression}} +#pragma omp declare reduction(fun : long & : \
omp_out += omp_in) // expected-error {{reduction type cannot be a \
reference type}} +#pragma omp declare reduction(fun : long(void) : omp_out += omp_in) \
// expected-error {{reduction type cannot be a function type}} +#pragma omp declare \
reduction(fun : long[3] : omp_out += omp_in) // expected-error {{reduction \
type cannot be an array type}} +#pragma omp declare reduction(fun23 : long, int, long \
: omp_out += omp_in) // expected-error {{previous declaration with type 'long' is \
found}} expected-note {{previous declaration is here}} +
+template <class T>
+class Class1 {
+#pragma omp declare reduction(fun : T : temp) // expected-error {{only \
'omp_in' or 'omp_out' variables are allowed in combiner expression}} +#pragma omp \
declare reduction(fun1 : T : omp_out++) // expected-note {{previous \
definition is here}} expected-error {{reduction type cannot be a reference type}} \
+#pragma omp declare reduction(fun1 : T : omp_out += omp_in) // expected-error \
{{redefinition of user-defined reduction for type 'T'}} +#pragma omp declare \
reduction(fun2 : T, T : omp_out++) // expected-error {{reduction type cannot be \
a reference type}} expected-error {{previous declaration with type 'T' is found}} \
expected-note {{previous declaration is here}} +};
+
+Class1<char &> e; // expected-note {{in instantiation of template class 'Class1<char \
&>' requested here}} +
+template <class T>
+class Class2 {
+#pragma omp declare reduction(fun : T : omp_out += omp_in)
+};
+
+#pragma omp declare reduction(fun222 : long : omp_out += omp_in) \
// expected-note {{previous definition is here}} +#pragma omp declare \
reduction(fun222 : long : omp_out += omp_in) \
// expected-error {{redefinition of user-defined reduction for type 'long'}} +#pragma \
omp declare reduction(fun1 : long : omp_out += omp_in) initializer \
// expected-error {{expected '(' after 'initializer'}} +#pragma omp declare \
reduction(fun2 : long : omp_out += omp_in) initializer { \
// expected-error {{expected '(' after 'initializer'}} expected-error {{expected \
expression}} expected-warning {{extra tokens at the end of '#pragma omp declare \
reduction' are ignored}} +#pragma omp declare reduction(fun3 : long : omp_out += \
omp_in) initializer[ // expected-error {{expected '(' \
after 'initializer'}} expected-error {{expected expression}} expected-warning {{extra \
tokens at the end of '#pragma omp declare reduction' are ignored}} +#pragma omp \
declare reduction(fun4 : long : omp_out += omp_in) initializer() \
// expected-error {{expected expression}} +#pragma omp declare reduction(fun5 : long \
: omp_out += omp_in) initializer(temp) // expected-error \
{{only 'omp_priv' or 'omp_orig' variables are allowed in initializer expression}} \
+#pragma omp declare reduction(fun6 : long : omp_out += omp_in) initializer(omp_orig \
// expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp \
declare reduction(fun7 : long : omp_out += omp_in) initializer(omp_priv Class1 < int \
> ()) // expected-error {{expected ')'}} expected-note {{to match this '('}} \
> +#pragma omp declare reduction(fun77 : long : omp_out += omp_in) \
> initializer(omp_priv Class2 < int > ()) // expected-error {{expected ')'}} \
> expected-note {{to match this '('}}
+#pragma omp declare reduction(fun8 : long : omp_out += omp_in) initializer(omp_priv \
23) // expected-error {{expected ')'}} expected-note {{to match this \
'('}} +#pragma omp declare reduction(fun88 : long : omp_out += omp_in) \
initializer(omp_priv 23)) // expected-error {{expected ')'}} \
expected-note {{to match this '('}} expected-warning {{extra tokens at the end of \
'#pragma omp declare reduction' are ignored}} +#pragma omp declare reduction(fun9 : \
long : omp_out += omp_priv) initializer(omp_in = 23) // expected-error \
{{use of undeclared identifier 'omp_priv'; did you mean 'omp_in'?}} expected-note \
{{'omp_in' is an implicit parameter}} +#pragma omp declare reduction(fun10 : long : \
omp_out += omp_in) initializer(omp_priv = 23) +
+template <typename T>
+T fun(T arg) {
+#pragma omp declare reduction(red : T : omp_out++)
+ {
+#pragma omp declare reduction(red : T : omp_out++) // expected-note {{previous \
definition is here}} +#pragma omp declare reduction(red : T : omp_out++) // \
expected-error {{redefinition of user-defined reduction for type 'T'}} +#pragma omp \
declare reduction(fun : T : omp_out += omp_in) initializer(omp_priv = 23) + }
+ return arg;
+}
+
+template <typename T>
+T foo(T arg) {
+ {
+#pragma omp declare reduction(red : T : omp_out++)
+#pragma omp declare reduction(red1 : T : omp_out++) // expected-note {{previous \
definition is here}} +#pragma omp declare reduction(red1 : int : omp_out++) // \
expected-error {{redefinition of user-defined reduction for type 'int'}} + }
+ {
+#pragma omp declare reduction(red1 : int : omp_out++) // expected-note {{previous \
definition is here}} +#pragma omp declare reduction(red : T : omp_out++)
+#pragma omp declare reduction(red1 : T : omp_out++) // expected-error {{redefinition \
of user-defined reduction for type 'int'}} + }
+ return arg;
+}
+#pragma omp declare reduction(foo : int : ({int a = omp_in; a = a * 2; omp_out += a; \
})) +int main() {
+ Class1<int> c1;
+ int i;
+ // TODO: Add support for scoped reduction identifiers
+ // #pragma omp parallel reduction (::fun : c1)
+ {
+ }
+ // #pragma omp parallel reduction (::Class1<int>::fun : c1)
+ {
+ }
+ // #pragma omp parallel reduction (::Class2<int>::fun : i)
+ {
+ }
+ return fun(15) + foo(15); // expected-note {{in instantiation of function template \
specialization 'foo<int>' requested here}} +}
Index: test/OpenMP/declare_reduction_ast_print.c
===================================================================
--- test/OpenMP/declare_reduction_ast_print.c
+++ test/OpenMP/declare_reduction_ast_print.c
@@ -0,0 +1,42 @@
+// 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 reduction(+ : int, char : omp_out *= omp_in)
+// CHECK: #pragma omp declare reduction (+ : int : omp_out *= omp_in)
+// CHECK-NEXT: #pragma omp declare reduction (+ : char : omp_out *= omp_in)
+
+#pragma omp declare reduction(fun : float : omp_out += omp_in) initializer(omp_priv \
= omp_orig + 15) +// CHECK: #pragma omp declare reduction (fun : float : omp_out += \
omp_in) initializer(omp_priv = omp_orig + 15) +
+// CHECK: struct SSS {
+struct SSS {
+ int field;
+#pragma omp declare reduction(+ : int, char : omp_out *= omp_in)
+ // CHECK: #pragma omp declare reduction (+ : int : omp_out *= omp_in)
+ // CHECK-NEXT: #pragma omp declare reduction (+ : char : omp_out *= omp_in)
+};
+// CHECK: };
+
+void init(struct SSS *priv, struct SSS orig);
+
+#pragma omp declare reduction(fun : struct SSS : omp_out = omp_in) \
initializer(init(&omp_priv, omp_orig)) +// CHECK: #pragma omp declare reduction (fun \
: struct SSS : omp_out = omp_in) initializer(init(&omp_priv, omp_orig)) +
+// CHECK: int main() {
+int main() {
+#pragma omp declare reduction(fun : struct SSS : omp_out = omp_in) \
initializer(init(&omp_priv, omp_orig)) + // CHECK: #pragma omp declare reduction \
(fun : struct SSS : omp_out = omp_in) initializer(init(&omp_priv, omp_orig)) + {
+#pragma omp declare reduction(fun : struct SSS : omp_out = omp_in) \
initializer(init(&omp_priv, omp_orig)) + // CHECK: #pragma omp declare reduction \
(fun : struct SSS : omp_out = omp_in) initializer(init(&omp_priv, omp_orig)) + }
+ return 0;
+}
+// CHECK: }
+
+#endif
_______________________________________________
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