summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorAlexey Bataev <a.bataev@hotmail.com>2016-03-03 05:21:39 +0000
committerAlexey Bataev <a.bataev@hotmail.com>2016-03-03 05:21:39 +0000
commit94a4f0cb5f8a44e1228f1fd06c8d970125084c71 (patch)
tree5e5bfcc492ec4e95123b4a51523a59da17ebebf5 /clang/lib/Sema
parent2a4985c929e93e623a2899f485f6f5f014bf4c83 (diff)
downloadbcm5719-llvm-94a4f0cb5f8a44e1228f1fd06c8d970125084c71.tar.gz
bcm5719-llvm-94a4f0cb5f8a44e1228f1fd06c8d970125084c71.zip
[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
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r--clang/lib/Sema/ScopeInfo.cpp1
-rw-r--r--clang/lib/Sema/SemaDecl.cpp5
-rw-r--r--clang/lib/Sema/SemaExpr.cpp13
-rw-r--r--clang/lib/Sema/SemaLookup.cpp8
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp232
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp75
6 files changed, 332 insertions, 2 deletions
diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp
index cbd7ef7abb4..ef9eed65ebc 100644
--- a/clang/lib/Sema/ScopeInfo.cpp
+++ b/clang/lib/Sema/ScopeInfo.cpp
@@ -28,6 +28,7 @@ void FunctionScopeInfo::Clear() {
HasBranchIntoScope = false;
HasIndirectGoto = false;
HasDroppedStmt = false;
+ HasOMPDeclareReductionCombiner = false;
ObjCShouldCallSuper = false;
ObjCIsDesignatedInit = false;
ObjCWarnForNoDesignatedInitChain = false;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index f7fe506f4ae..f20b4d06287 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -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;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 0ca5555e1da..b644ff215cd 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -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);
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 4baf6053359..00379336251 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -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.
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 50148b5187c..ffac56b1ddd 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -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,
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index af93cde68c1..c021b34a4e5 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -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");
OpenPOWER on IntegriCloud