[OPENMP 4.0] Initial support for 'omp declare reduction' construct.

Add parsing, sema analysis and serialization/deserialization for 'declare reduction' construct.
User-defined reductions are defined as

#pragma omp declare reduction( reduction-identifier : typename-list : combiner ) [initializer ( initializer-expr )]
These custom reductions may be used in 'reduction' clauses of OpenMP constructs. The combiner specifies how partial results can be combined into a single value. The
combiner can use the special variable identifiers omp_in and omp_out that are of the type of the variables being reduced with this reduction-identifier. Each of them will
denote one of the values to be combined before executing the combiner. It is assumed that the special omp_out identifier will refer to the storage that holds the resulting
combined value after executing the combiner.
As the initializer-expr value of a user-defined reduction is not known a priori the initializer-clause can be used to specify one. Then the contents of the initializer-clause
will be used as the initializer for private copies of reduction list items where the omp_priv identifier will refer to the storage to be initialized. The special identifier
omp_orig can also appear in the initializer-clause and it will refer to the storage of the original variable to be reduced.
Differential Revision: http://reviews.llvm.org/D11182

llvm-svn: 262582
This commit is contained in:
Alexey Bataev 2016-03-03 05:21:39 +00:00
parent 2a4985c929
commit 94a4f0cb5f
41 changed files with 1150 additions and 26 deletions

View File

@ -166,7 +166,10 @@ public:
/// has been declared outside any function. These act mostly like
/// invisible friend declarations, but are also visible to unqualified
/// lookup within the scope of the declaring 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
@ -256,7 +259,7 @@ private:
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;
@ -296,7 +299,7 @@ protected:
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.
@ -1117,6 +1120,7 @@ public:
/// ObjCContainerDecl
/// LinkageSpecDecl
/// BlockDecl
/// OMPDeclareReductionDecl
///
class DeclContext {
/// DeclKind - This indicates which class this is.

View File

@ -1570,6 +1570,14 @@ public:
static bool FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, DeclarationName Name);
/// \brief Base-class lookup callback that determines whether there exists
/// an OpenMP declare reduction member with the given name.
///
/// This callback can be used with \c lookupInBases() to find members
/// of the given name within a C++ class hierarchy.
static bool FindOMPReductionMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path, DeclarationName Name);
/// \brief Base-class lookup callback that determines whether there exists
/// a member with the given name that can be used in a nested-name-specifier.
///

View File

@ -15,12 +15,14 @@
#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/ExternalASTSource.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/TrailingObjects.h"
namespace clang {
class Expr;
/// \brief This represents '#pragma omp threadprivate ...' directive.
/// For example, in the following, both 'a' and 'A::b' are threadprivate:
@ -87,6 +89,83 @@ public:
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 final : public NamedDecl, public DeclContext {
private:
friend class ASTDeclReader;
/// \brief Combiner for declare reduction construct.
Expr *Combiner;
/// \brief Initializer for declare reduction construct.
Expr *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.
LazyDeclPtr PrevDeclInScope;
/// \brief Type of declare reduction construct.
QualType Ty;
virtual void anchor();
OMPDeclareReductionDecl(Kind DK, DeclContext *DC, SourceLocation L,
DeclarationName Name, QualType Ty,
OMPDeclareReductionDecl *PrevDeclInScope)
: NamedDecl(DK, DC, L, Name), DeclContext(DK), Combiner(nullptr),
Initializer(nullptr), PrevDeclInScope(PrevDeclInScope), Ty(Ty) {}
void setPrevDeclInScope(OMPDeclareReductionDecl *Prev) {
PrevDeclInScope = Prev;
}
void setType(QualType T) { Ty = T; }
public:
/// \brief Create declare reduction node.
static OMPDeclareReductionDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name,
QualType T, OMPDeclareReductionDecl *PrevDeclInScope);
/// \brief Create deserialized declare reduction node.
static OMPDeclareReductionDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
/// \brief Get combiner expression of the declare reduction construct.
Expr *getCombiner() { return Combiner; }
const Expr *getCombiner() const { return 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 Initializer; }
const Expr *getInitializer() const { return 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 *getPrevDeclInScope();
const OMPDeclareReductionDecl *getPrevDeclInScope() const;
QualType getType() const { return Ty; }
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));
}
};
/// Pseudo declaration for capturing expressions. Also is used for capturing of
/// non-static data members in non-static member functions.
///

View File

@ -1467,6 +1467,14 @@ DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, {
}
})
DEF_TRAVERSE_DECL(OMPDeclareReductionDecl, {
TRY_TO(TraverseStmt(D->getCombiner()));
if (auto *Initializer = D->getInitializer())
TRY_TO(TraverseStmt(Initializer));
TRY_TO(TraverseType(D->getType()));
return true;
})
DEF_TRAVERSE_DECL(OMPCapturedExprDecl, { TRY_TO(TraverseVarHelper(D)); })
// A helper method for TemplateDecl's children.

View File

@ -75,6 +75,7 @@ def Named : Decl<1>;
def ObjCImplementation : DDecl<ObjCImpl>;
def ObjCProperty : DDecl<Named>;
def ObjCCompatibleAlias : DDecl<Named>;
def OMPDeclareReduction : DDecl<Named>, DeclContext;
def LinkageSpec : Decl, DeclContext;
def ObjCPropertyImpl : Decl;
def FileScopeAsm : Decl;

View File

@ -939,6 +939,8 @@ def err_omp_immediate_directive : Error<
"'#pragma omp %0' %select{|with '%2' clause }1cannot 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: '+', '-', '*', '&', '|', '^', '&&', or '||'">;
def err_omp_unknown_map_type : Error<
"incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'">;
def err_omp_unknown_map_type_modifier : Error<

View File

@ -7992,6 +7992,9 @@ def err_omp_parent_cancel_region_nowait : Error<
"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_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">;
def err_omp_array_section_use : Error<"OpenMP array section is not allowed here">;
def err_omp_typecheck_section_value : Error<
"subscripted value is not an array or pointer">;

View File

@ -155,6 +155,7 @@ OPENMP_DIRECTIVE_EXT(parallel_for_simd, "parallel for simd")
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_DIRECTIVE(taskloop)
OPENMP_DIRECTIVE_EXT(taskloop_simd, "taskloop simd")
OPENMP_DIRECTIVE(distribute)

View File

@ -2454,7 +2454,9 @@ private:
//===--------------------------------------------------------------------===//
// 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.

View File

@ -104,6 +104,9 @@ public:
/// \brief Whether a statement was dropped because it was invalid.
bool HasDroppedStmt : 1;
/// \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)).
@ -341,6 +344,10 @@ public:
HasDroppedStmt = true;
}
void setHasOMPDeclareReductionCombiner() {
HasOMPDeclareReductionCombiner = true;
}
void setHasCXXTry(SourceLocation TryLoc) {
setHasBranchProtectedScope();
FirstCXXTryLoc = TryLoc;
@ -363,6 +370,7 @@ public:
HasBranchIntoScope(false),
HasIndirectGoto(false),
HasDroppedStmt(false),
HasOMPDeclareReductionCombiner(false),
ObjCShouldCallSuper(false),
ObjCIsDesignatedInit(false),
ObjCWarnForNoDesignatedInitChain(false),

View File

@ -145,6 +145,7 @@ namespace clang {
class ObjCPropertyDecl;
class ObjCProtocolDecl;
class OMPThreadPrivateDecl;
class OMPDeclareReductionDecl;
class OMPClause;
struct OverloadCandidate;
class OverloadCandidateSet;
@ -2671,6 +2672,8 @@ public:
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
};
@ -7872,6 +7875,26 @@ public:
OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl(
SourceLocation Loc,
ArrayRef<Expr *> VarList);
/// \brief Check if the specified type is allowed to be used in 'omp declare
/// reduction' construct.
QualType ActOnOpenMPDeclareReductionType(SourceLocation TyLoc,
TypeResult ParsedType);
/// \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 *PrevDeclInScope = 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 at the end of '#pragma omp declare reduction'.
DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd(
Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid);
/// \brief Initialization of captured region for OpenMP region.
void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope);

View File

@ -1174,7 +1174,9 @@ namespace clang {
/// \brief A PragmaCommentDecl record.
DECL_PRAGMA_COMMENT,
/// \brief A PragmaDetectMismatchDecl record.
DECL_PRAGMA_DETECT_MISMATCH
DECL_PRAGMA_DETECT_MISMATCH,
/// \brief An OMPDeclareReductionDecl record.
DECL_OMP_DECLARE_REDUCTION,
};
/// \brief Record codes for each kind of statement or expression.

View File

@ -405,6 +405,21 @@ bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
return false;
}
bool CXXRecordDecl::FindOMPReductionMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name) {
RecordDecl *BaseRecord =
Specifier->getType()->castAs<RecordType>()->getDecl();
for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty();
Path.Decls = Path.Decls.slice(1)) {
if (Path.Decls.front()->isInIdentifierNamespace(IDNS_OMPReduction))
return true;
}
return false;
}
bool CXXRecordDecl::
FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,

View File

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

View File

@ -633,6 +633,9 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case TemplateTemplateParm:
return IDNS_Ordinary | IDNS_Tag | IDNS_Type;
case OMPDeclareReduction:
return IDNS_OMPReduction;
// Never have names.
case Friend:
case FriendTemplate:
@ -963,6 +966,7 @@ DeclContext *DeclContext::getPrimaryContext() {
case Decl::LinkageSpec:
case Decl::Block:
case Decl::Captured:
case Decl::OMPDeclareReduction:
// There is only one DeclContext for these entities.
return this;

View File

@ -53,6 +53,36 @@ void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) {
std::uninitialized_copy(VL.begin(), VL.end(), getTrailingObjects<Expr *>());
}
//===----------------------------------------------------------------------===//
// OMPDeclareReductionDecl Implementation.
//===----------------------------------------------------------------------===//
void OMPDeclareReductionDecl::anchor() {}
OMPDeclareReductionDecl *OMPDeclareReductionDecl::Create(
ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name,
QualType T, OMPDeclareReductionDecl *PrevDeclInScope) {
return new (C, DC) OMPDeclareReductionDecl(OMPDeclareReduction, DC, L, Name,
T, PrevDeclInScope);
}
OMPDeclareReductionDecl *
OMPDeclareReductionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) OMPDeclareReductionDecl(
OMPDeclareReduction, /*DC=*/nullptr, SourceLocation(), DeclarationName(),
QualType(), /*PrevDeclInScope=*/nullptr);
}
OMPDeclareReductionDecl *OMPDeclareReductionDecl::getPrevDeclInScope() {
return cast_or_null<OMPDeclareReductionDecl>(
PrevDeclInScope.get(getASTContext().getExternalSource()));
}
const OMPDeclareReductionDecl *
OMPDeclareReductionDecl::getPrevDeclInScope() const {
return cast_or_null<OMPDeclareReductionDecl>(
PrevDeclInScope.get(getASTContext().getExternalSource()));
}
//===----------------------------------------------------------------------===//
// OMPCapturedExprDecl Implementation.
//===----------------------------------------------------------------------===//

View File

@ -92,6 +92,7 @@ namespace {
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
void PrintTemplateParameters(const TemplateParameterList *Params,
@ -334,7 +335,7 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
// 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())
@ -1367,6 +1368,37 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
}
}
void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
if (!D->isInvalidDecl()) {
Out << "#pragma omp declare reduction (";
if (D->getDeclName().getNameKind() == DeclarationName::CXXOperatorName) {
static const char *const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
nullptr,
#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
Spelling,
#include "clang/Basic/OperatorKinds.def"
};
const char *OpName =
OperatorNames[D->getDeclName().getCXXOverloadedOperator()];
assert(OpName && "not an overloaded operator");
Out << OpName;
} else {
assert(D->getDeclName().isIdentifier());
D->printName(Out);
}
Out << " : ";
D->getType().print(Out, Policy);
Out << " : ";
D->getCombiner()->printPretty(Out, nullptr, Policy, 0);
Out << ")";
if (auto *Init = D->getInitializer()) {
Out << " initializer(";
Init->printPretty(Out, nullptr, Policy, 0);
Out << ")";
}
}
}
void DeclPrinter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
D->getInit()->printPretty(Out, nullptr, Policy, Indentation);
}

View File

@ -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"
@ -66,8 +67,9 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) {
}
const DeclContext *DC = D->getDeclContext();
if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC))
return getEffectiveDeclContext(CD);
if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC)) {
return getEffectiveDeclContext(cast<Decl>(DC));
}
if (const auto *VD = dyn_cast<VarDecl>(D))
if (VD->isExternC())

View File

@ -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"
@ -58,8 +59,9 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) {
}
const DeclContext *DC = D->getDeclContext();
if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC))
return getEffectiveDeclContext(CD);
if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC)) {
return getEffectiveDeclContext(cast<Decl>(DC));
}
return DC;
}

View File

@ -554,6 +554,7 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
case OMPD_taskwait:
case OMPD_taskgroup:
case OMPD_cancellation_point:
case OMPD_declare_reduction:
break;
}
return false;

View File

@ -21,6 +21,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"
@ -118,6 +119,9 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
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);
@ -1862,3 +1866,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
if (D.hasAttr<AnnotateAttr>())
EmitVarAnnotations(&D, DeclPtr.getPointer());
}
void CodeGenModule::EmitOMPDeclareReduction(
const OMPDeclareReductionDecl * /*D*/) {}

View File

@ -3796,6 +3796,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
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

View File

@ -21,6 +21,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"
@ -1110,6 +1111,9 @@ public:
/// \param D Threadprivate declaration.
void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D);
/// \brief Emit a code for declare reduction construct.
void EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D);
/// Returns whether we need bit sets attached to vtables.
bool NeedVTableBitSets();

View File

@ -3644,13 +3644,11 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
}
if (Tok.is(tok::annot_pragma_openmp)) {
// Result can be ignored, because it must be always empty.
auto Res = ParseOpenMPDeclarativeDirective();
assert(!Res);
// Silence possible warnings.
(void)Res;
// There may be declared reduction operator inside structure/union.
(void)ParseOpenMPDeclarativeDirective(AS_public);
continue;
}
if (!Tok.is(tok::at)) {
auto CFieldCallback = [&](ParsingFieldDeclarator &FD) {
// Install the declarator into the current TagDecl.

View File

@ -2910,7 +2910,7 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas(
}
if (Tok.is(tok::annot_pragma_openmp))
return ParseOpenMPDeclarativeDirective();
return ParseOpenMPDeclarativeDirective(AS);
// Parse all the comma separated declarators.
return ParseCXXClassMemberDeclaration(AS, AccessAttrs.getList());

View File

@ -30,9 +30,11 @@ namespace {
enum OpenMPDirectiveKindEx {
OMPD_cancellation = OMPD_unknown + 1,
OMPD_data,
OMPD_declare,
OMPD_enter,
OMPD_exit,
OMPD_point,
OMPD_reduction,
OMPD_target_enter,
OMPD_target_exit
};
@ -48,9 +50,11 @@ static unsigned getOpenMPDirectiveKindEx(StringRef S) {
return llvm::StringSwitch<unsigned>(S)
.Case("cancellation", OMPD_cancellation)
.Case("data", OMPD_data)
.Case("declare", OMPD_declare)
.Case("enter", OMPD_enter)
.Case("exit", OMPD_exit)
.Case("point", OMPD_point)
.Case("reduction", OMPD_reduction)
.Default(OMPD_unknown);
}
@ -60,6 +64,7 @@ static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) {
// TODO: add other combined directives in topological order.
static const unsigned F[][3] = {
{ OMPD_cancellation, OMPD_point, OMPD_cancellation_point },
{ OMPD_declare, OMPD_reduction, OMPD_declare_reduction },
{ OMPD_target, OMPD_data, OMPD_target_data },
{ OMPD_target, OMPD_enter, OMPD_target_enter },
{ OMPD_target, OMPD_exit, OMPD_target_exit },
@ -73,6 +78,7 @@ static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) {
{ OMPD_target, OMPD_parallel, OMPD_target_parallel },
{ OMPD_target_parallel, OMPD_for, OMPD_target_parallel_for }
};
enum { CancellationPoint = 0, DeclareReduction = 1, TargetData = 2 };
auto Tok = P.getCurToken();
unsigned DKind =
Tok.isAnnotation()
@ -98,16 +104,226 @@ static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) {
DKind = F[i][2];
}
}
return DKind <= OMPD_unknown ? static_cast<OpenMPDirectiveKind>(DKind)
: OMPD_unknown;
return DKind < OMPD_unknown ? static_cast<OpenMPDirectiveKind>(DKind)
: OMPD_unknown;
}
static DeclarationName parseOpenMPReductionId(Parser &P) {
const Token Tok = P.getCurToken();
Sema &Actions = P.getActions();
OverloadedOperatorKind OOK = OO_None;
switch (Tok.getKind()) {
case tok::plus: // '+'
OOK = OO_Plus;
break;
case tok::minus: // '-'
OOK = OO_Minus;
break;
case tok::star: // '*'
OOK = OO_Star;
break;
case tok::amp: // '&'
OOK = OO_Amp;
break;
case tok::pipe: // '|'
OOK = OO_Pipe;
break;
case tok::caret: // '^'
OOK = OO_Caret;
break;
case tok::ampamp: // '&&'
OOK = OO_AmpAmp;
break;
case tok::pipepipe: // '||'
OOK = OO_PipePipe;
break;
case tok::identifier: // identifier
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);
return DeclarationName();
}
P.ConsumeToken();
auto &DeclNames = Actions.getASTContext().DeclarationNames;
return OOK == OO_None ? DeclNames.getIdentifier(Tok.getIdentifierInfo())
: DeclNames.getCXXOperatorName(OOK);
}
/// \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();
// Consume ':'.
bool IsCorrect = !ExpectAndConsume(tok::colon);
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;
// Parse list of types until ':' token.
do {
ColonProtectionRAIIObject ColonRAII(*this);
SourceRange Range;
TypeResult TR = ParseTypeName(&Range, Declarator::PrototypeContext, AS);
if (TR.isUsable()) {
auto ReductionType =
Actions.ActOnOpenMPDeclareReductionType(Range.getBegin(), TR);
if (!ReductionType.isNull()) {
ReductionTypes.push_back(
std::make_pair(ReductionType, Range.getBegin()));
}
} else {
SkipUntil(tok::comma, tok::colon, tok::annot_pragma_openmp_end,
StopBeforeMatch);
}
if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end))
break;
// Consume ','.
if (ExpectAndConsume(tok::comma)) {
IsCorrect = false;
if (Tok.is(tok::annot_pragma_openmp_end)) {
Diag(Tok.getLocation(), diag::err_expected_type);
return DeclGroupPtrTy();
}
}
} while (Tok.isNot(tok::annot_pragma_openmp_end));
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 (ExpectAndConsume(tok::colon))
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.isUsable();
ExprResult InitializerResult;
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
// Parse <initializer> expression.
if (Tok.is(tok::identifier) &&
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();
}
}
++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,
IsCorrect);
}
/// \brief Parsing of declarative OpenMP directives.
///
/// threadprivate-directive:
/// annot_pragma_openmp 'threadprivate' simple-variable-list
/// annot_pragma_openmp_end
///
Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
/// declare-reduction-directive:
/// annot_pragma_openmp 'declare' 'reduction' [...]
/// annot_pragma_openmp_end
///
Parser::DeclGroupPtrTy
Parser::ParseOpenMPDeclarativeDirective(AccessSpecifier AS) {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@ -131,6 +347,22 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
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);
while (Tok.isNot(tok::annot_pragma_openmp_end))
ConsumeAnyToken();
}
// Skip the last annot_pragma_openmp_end.
ConsumeToken();
return Res;
}
break;
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
break;
@ -170,7 +402,9 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
<< getOpenMPDirectiveName(DKind);
break;
}
SkipUntil(tok::annot_pragma_openmp_end);
while (Tok.isNot(tok::annot_pragma_openmp_end))
ConsumeAnyToken();
ConsumeAnyToken();
return nullptr;
}
@ -180,6 +414,12 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
/// 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> ')' ] |
@ -231,6 +471,22 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
}
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);
while (Tok.isNot(tok::annot_pragma_openmp_end))
ConsumeAnyToken();
}
ConsumeAnyToken();
Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
} else
SkipUntil(tok::annot_pragma_openmp_end);
break;
case OMPD_flush:
if (PP.LookAhead(0).is(tok::l_paren)) {
FlushHasClause = true;

View File

@ -659,7 +659,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
HandlePragmaOpenCLExtension();
return nullptr;
case tok::annot_pragma_openmp:
return ParseOpenMPDeclarativeDirective();
return ParseOpenMPDeclarativeDirective(/*AS=*/AS_none);
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
return nullptr;

View File

@ -28,6 +28,7 @@ void FunctionScopeInfo::Clear() {
HasBranchIntoScope = false;
HasIndirectGoto = false;
HasDroppedStmt = false;
HasOMPDeclareReductionCombiner = false;
ObjCShouldCallSuper = false;
ObjCIsDesignatedInit = false;
ObjCWarnForNoDesignatedInitChain = false;

View File

@ -5640,7 +5640,7 @@ static bool isIncompleteDeclExternC(Sema &S, const T *D) {
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;
@ -5651,7 +5651,8 @@ static bool shouldConsiderLinkage(const VarDecl *VD) {
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;

View File

@ -376,6 +376,19 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
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);

View File

@ -280,6 +280,10 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
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
@ -2015,6 +2019,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
BaseCallback = &LookupAnyMember;
break;
case LookupOMPReductionName:
BaseCallback = &CXXRecordDecl::FindOMPReductionMember;
break;
case LookupUsingDeclName:
// This lookup is for redeclarations only.

View File

@ -21,6 +21,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
@ -1698,6 +1699,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_flush:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
case OMPD_declare_reduction:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
@ -3139,6 +3141,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
EndLoc, VarsWithInheritedDSA);
break;
case OMPD_threadprivate:
case OMPD_declare_reduction:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
@ -9584,6 +9587,235 @@ Sema::ActOnOpenMPMapClause(OpenMPMapClauseKind MapTypeModifier,
MapLoc);
}
QualType Sema::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc,
TypeResult ParsedType) {
assert(ParsedType.isUsable());
QualType ReductionType = GetTypeFromParser(ParsedType.get());
if (ReductionType.isNull())
return QualType();
// [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 QualType();
}
if (ReductionType->isFunctionType()) {
Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 1;
return QualType();
}
if (ReductionType->isReferenceType()) {
Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 2;
return QualType();
}
if (ReductionType->isArrayType()) {
Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 3;
return QualType();
}
return ReductionType;
}
Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart(
Scope *S, DeclContext *DC, DeclarationName Name,
ArrayRef<std::pair<QualType, SourceLocation>> ReductionTypes,
AccessSpecifier AS, Decl *PrevDeclInScope) {
SmallVector<Decl *, 8> Decls;
Decls.reserve(ReductionTypes.size());
LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPReductionName,
ForRedeclaration);
// [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.
llvm::DenseMap<QualType, SourceLocation> PreviousRedeclTypes;
OMPDeclareReductionDecl *PrevDRD = nullptr;
bool InCompoundScope = true;
if (S != nullptr) {
// Find previous declaration with the same name not referenced in other
// declarations.
FunctionScopeInfo *ParentFn = getEnclosingFunction();
InCompoundScope =
(ParentFn != nullptr) && !ParentFn->CompoundScopes.empty();
LookupName(Lookup, S);
FilterLookupForScope(Lookup, DC, S, /*ConsiderLinkage=*/false,
/*AllowInlineNamespace=*/false);
llvm::DenseMap<OMPDeclareReductionDecl *, bool> UsedAsPrevious;
auto Filter = Lookup.makeFilter();
while (Filter.hasNext()) {
auto *PrevDecl = cast<OMPDeclareReductionDecl>(Filter.next());
if (InCompoundScope) {
auto I = UsedAsPrevious.find(PrevDecl);
if (I == UsedAsPrevious.end())
UsedAsPrevious[PrevDecl] = false;
if (auto *D = PrevDecl->getPrevDeclInScope())
UsedAsPrevious[D] = true;
}
PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] =
PrevDecl->getLocation();
}
Filter.done();
if (InCompoundScope) {
for (auto &PrevData : UsedAsPrevious) {
if (!PrevData.second) {
PrevDRD = PrevData.first;
break;
}
}
}
} else if (PrevDeclInScope != nullptr) {
auto *PrevDRDInScope = PrevDRD =
cast<OMPDeclareReductionDecl>(PrevDeclInScope);
do {
PreviousRedeclTypes[PrevDRDInScope->getType().getCanonicalType()] =
PrevDRDInScope->getLocation();
PrevDRDInScope = PrevDRDInScope->getPrevDeclInScope();
} while (PrevDRDInScope != nullptr);
}
for (auto &TyData : ReductionTypes) {
auto I = PreviousRedeclTypes.find(TyData.first.getCanonicalType());
bool Invalid = false;
if (I != PreviousRedeclTypes.end()) {
Diag(TyData.second, diag::err_omp_declare_reduction_redefinition)
<< TyData.first;
Diag(I->second, diag::note_previous_definition);
Invalid = true;
}
PreviousRedeclTypes[TyData.first.getCanonicalType()] = TyData.second;
auto *DRD = OMPDeclareReductionDecl::Create(Context, DC, TyData.second,
Name, TyData.first, PrevDRD);
DC->addDecl(DRD);
DRD->setAccess(AS);
Decls.push_back(DRD);
if (Invalid)
DRD->setInvalidDecl();
else
PrevDRD = 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 != nullptr)
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_parm;T omp_out;'. All references to 'omp_out' will
// be replaced by '*omp_parm' during codegen. This required because 'omp_out'
// uses semantics of argument handles by value, but it should be passed by
// reference. C lang does not support references, so pass all parameters as
// pointers.
// Create 'T omp_out;' variable.
auto *OmpOutParm =
buildVarDecl(*this, D->getLocation(), ReductionType, "omp_out");
if (S != nullptr) {
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 != nullptr)
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 != nullptr)
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_parm;T omp_priv;'. All references to 'omp_priv' will
// be replaced by '*omp_parm' during codegen. This required because 'omp_priv'
// uses semantics of argument handles by value, but it should be passed by
// reference. C lang does not support references, so pass all parameters as
// pointers.
// Create 'T omp_priv;' variable.
auto *OmpPrivParm =
buildVarDecl(*this, D->getLocation(), ReductionType, "omp_priv");
if (S != nullptr) {
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 != nullptr)
DRD->setInitializer(Initializer);
else
DRD->setInvalidDecl();
}
Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd(
Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid) {
for (auto *D : DeclReductions.get()) {
if (IsValid) {
auto *DRD = cast<OMPDeclareReductionDecl>(D);
if (S != nullptr)
PushOnScopeChains(DRD, S, /*AddToContext=*/false);
} else
D->setInvalidDecl();
}
return DeclReductions;
}
OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams,
SourceLocation StartLoc,
SourceLocation LParenLoc,

View File

@ -2503,6 +2503,81 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
return TD;
}
Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
OMPDeclareReductionDecl *D) {
// Instantiate type and check if it is allowed.
QualType SubstReductionType = SemaRef.ActOnOpenMPDeclareReductionType(
D->getLocation(),
ParsedType::make(SemaRef.SubstType(D->getType(), TemplateArgs,
D->getLocation(), DeclarationName())));
if (SubstReductionType.isNull())
return nullptr;
bool IsCorrect = !SubstReductionType.isNull();
// Create instantiated copy.
std::pair<QualType, SourceLocation> ReductionTypes[] = {
std::make_pair(SubstReductionType, D->getLocation())};
auto *PrevDeclInScope = D->getPrevDeclInScope();
if (PrevDeclInScope && !PrevDeclInScope->isInvalidDecl()) {
PrevDeclInScope = cast<OMPDeclareReductionDecl>(
SemaRef.CurrentInstantiationScope->findInstantiationOf(PrevDeclInScope)
->get<Decl *>());
}
auto DRD = SemaRef.ActOnOpenMPDeclareReductionDirectiveStart(
/*S=*/nullptr, Owner, D->getDeclName(), ReductionTypes, D->getAccess(),
PrevDeclInScope);
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);
const char *Names[] = {"omp_in", "omp_out"};
for (auto &Name : Names) {
DeclarationName DN(&SemaRef.Context.Idents.get(Name));
auto OldLookup = D->lookup(DN);
auto Lookup = NewDRD->lookup(DN);
if (!OldLookup.empty() && !Lookup.empty()) {
assert(Lookup.size() == 1 && OldLookup.size() == 1);
SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldLookup.front(),
Lookup.front());
}
}
SubstCombiner = SemaRef.SubstExpr(D->getCombiner(), TemplateArgs).get();
SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner);
// Initializers instantiation sequence.
if (D->getInitializer()) {
SemaRef.ActOnOpenMPDeclareReductionInitializerStart(
/*S=*/nullptr, NewDRD);
const char *Names[] = {"omp_orig", "omp_priv"};
for (auto &Name : Names) {
DeclarationName DN(&SemaRef.Context.Idents.get(Name));
auto OldLookup = D->lookup(DN);
auto Lookup = NewDRD->lookup(DN);
if (!OldLookup.empty() && !Lookup.empty()) {
assert(Lookup.size() == 1 && OldLookup.size() == 1);
SemaRef.CurrentInstantiationScope->InstantiatedLocal(
OldLookup.front(), Lookup.front());
}
}
SubstInitializer =
SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get();
SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(NewDRD,
SubstInitializer);
}
IsCorrect = IsCorrect && SubstCombiner &&
(!D->getInitializer() || SubstInitializer);
} else
IsCorrect = false;
(void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(/*S=*/nullptr, DRD,
IsCorrect);
return NewDRD;
}
Decl *TemplateDeclInstantiator::VisitOMPCapturedExprDecl(
OMPCapturedExprDecl * /*D*/) {
llvm_unreachable("Should not be met in templates");

View File

@ -332,6 +332,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::Import:
case Decl::OMPThreadPrivate:
case Decl::OMPCapturedExpr:
case Decl::OMPDeclareReduction:
case Decl::BuiltinTemplate:
return false;

View File

@ -356,6 +356,7 @@ namespace clang {
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
/// We've merged the definition \p MergedDef into the existing definition
@ -2394,6 +2395,15 @@ void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
D->setVars(Vars);
}
void ASTDeclReader::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
VisitNamedDecl(D);
D->setLocation(Reader.ReadSourceLocation(F, Record, Idx));
D->setCombiner(Reader.ReadExpr(F));
D->setInitializer(Reader.ReadExpr(F));
D->PrevDeclInScope = Reader.ReadDeclID(F, Record, Idx);
D->setType(Reader.readType(F, Record, Idx));
}
void ASTDeclReader::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
VisitVarDecl(D);
}
@ -2449,7 +2459,8 @@ static bool isConsumerInterestedIn(Decl *D, bool HasBody) {
isa<ImportDecl>(D) ||
isa<PragmaCommentDecl>(D) ||
isa<PragmaDetectMismatchDecl>(D) ||
isa<OMPThreadPrivateDecl>(D))
isa<OMPThreadPrivateDecl>(D) ||
isa<OMPDeclareReductionDecl>(D))
return true;
if (VarDecl *Var = dyn_cast<VarDecl>(D))
return Var->isFileVarDecl() &&
@ -3363,6 +3374,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
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_OMP_CAPTUREDEXPR:
D = OMPCapturedExprDecl::CreateDeserialized(Context, ID);
break;

View File

@ -133,6 +133,7 @@ namespace clang {
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
/// Add an Objective-C type parameter list to the given record.
@ -1653,6 +1654,16 @@ void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
Code = serialization::DECL_OMP_THREADPRIVATE;
}
void ASTDeclWriter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
VisitNamedDecl(D);
Writer.AddSourceLocation(D->getLocStart(), Record);
Writer.AddStmt(D->getCombiner());
Writer.AddStmt(D->getInitializer());
Writer.AddDeclRef(D->getPrevDeclInScope(), Record);
Writer.AddTypeRef(D->getType(), Record);
Code = serialization::DECL_OMP_DECLARE_REDUCTION;
}
void ASTDeclWriter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
VisitVarDecl(D);
Code = serialization::DECL_OMP_CAPTUREDEXPR;

View File

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

View File

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

View File

@ -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: '+', '-', '*', '&', '|', '^', '&&', or '||'}}
#pragma omp declare reduction(# // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&', or '||'}}
#pragma omp declare reduction(/ // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&', or '||'}}
#pragma omp declare reduction(+ // expected-error {{expected ':'}}
#pragma omp declare reduction(for // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&', or '||'}}
#pragma omp declare reduction(if: // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&', or '||'}} 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 {{redefinition of user-defined reduction for type 'long'}} expected-note {{previous definition 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;
}

View File

@ -0,0 +1,106 @@
// 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: '+', '-', '*', '&', '|', '^', '&&', or '||'}}
#pragma omp declare reduction(# // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&', or '||'}}
#pragma omp declare reduction(/ // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&', or '||'}}
#pragma omp declare reduction(+ // expected-error {{expected ':'}}
#pragma omp declare reduction(operator // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&', or '||'}}
#pragma omp declare reduction(operator: // expected-error {{expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&', or '||'}} 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 {{redefinition of user-defined reduction for type 'long'}} expected-note {{previous definition is here}}
template <class T>
class Class1 {
T a;
public:
Class1() : a() {}
#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 {{redefinition of user-defined reduction for type 'T'}} expected-note {{previous definition is here}}
#pragma omp declare reduction(foo : T : omp_out += this->a) // expected-error {{invalid use of 'this' outside of a non-static member function}}
};
Class1<char &> e; // expected-note {{in instantiation of template class 'Class1<char &>' requested here}}
template <class T>
class Class2 : public Class1<T> {
#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}}
}

View File

@ -5584,6 +5584,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::ClassScopeFunctionSpecialization:
case Decl::Import:
case Decl::OMPThreadPrivate:
case Decl::OMPDeclareReduction:
case Decl::ObjCTypeParam:
case Decl::BuiltinTemplate:
case Decl::PragmaComment: