summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntime.cpp58
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntime.h3
-rw-r--r--clang/lib/CodeGen/CGStmtOpenMP.cpp155
-rw-r--r--clang/lib/Parse/ParseOpenMP.cpp21
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp540
-rw-r--r--clang/lib/Sema/TreeTransform.h29
6 files changed, 588 insertions, 218 deletions
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index 64af40bd282..5bf12e39c10 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -622,12 +622,12 @@ emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty,
auto &C = CGM.getContext();
QualType PtrTy = C.getPointerType(Ty).withRestrict();
FunctionArgList Args;
- ImplicitParamDecl OmpInParm(C, /*DC=*/nullptr, In->getLocation(),
- /*Id=*/nullptr, PtrTy);
ImplicitParamDecl OmpOutParm(C, /*DC=*/nullptr, Out->getLocation(),
/*Id=*/nullptr, PtrTy);
- Args.push_back(&OmpInParm);
+ ImplicitParamDecl OmpInParm(C, /*DC=*/nullptr, In->getLocation(),
+ /*Id=*/nullptr, PtrTy);
Args.push_back(&OmpOutParm);
+ Args.push_back(&OmpInParm);
auto &FnInfo =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, Args);
auto *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
@@ -635,6 +635,7 @@ emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty,
FnTy, llvm::GlobalValue::InternalLinkage,
IsCombiner ? ".omp_combiner." : ".omp_initializer.", &CGM.getModule());
CGM.SetInternalFunctionAttributes(/*D=*/nullptr, Fn, FnInfo);
+ Fn->addFnAttr(llvm::Attribute::AlwaysInline);
CodeGenFunction CGF(CGM);
// Map "T omp_in;" variable to "*omp_in_parm" value in all expressions.
// Map "T omp_out;" variable to "*omp_out_parm" value in all expressions.
@@ -688,6 +689,15 @@ void CGOpenMPRuntime::emitUserDefinedReduction(
}
}
+std::pair<llvm::Function *, llvm::Function *>
+CGOpenMPRuntime::getUserDefinedReduction(const OMPDeclareReductionDecl *D) {
+ auto I = UDRMap.find(D);
+ if (I != UDRMap.end())
+ return I->second;
+ emitUserDefinedReduction(/*CGF=*/nullptr, D);
+ return UDRMap.lookup(D);
+}
+
// Layout information for ident_t.
static CharUnits getIdentAlign(CodeGenModule &CGM) {
return CGM.getPointerAlign();
@@ -3596,6 +3606,26 @@ static void EmitOMPAggregateReduction(
CGF.EmitBlock(DoneBB, /*IsFinished=*/true);
}
+/// Emit reduction combiner. If the combiner is a simple expression emit it as
+/// is, otherwise consider it as combiner of UDR decl and emit it as a call of
+/// UDR combiner function.
+static void emitReductionCombiner(CodeGenFunction &CGF,
+ const Expr *ReductionOp) {
+ if (auto *CE = dyn_cast<CallExpr>(ReductionOp))
+ if (auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
+ if (auto *DRE =
+ dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
+ if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl())) {
+ std::pair<llvm::Function *, llvm::Function *> Reduction =
+ CGF.CGM.getOpenMPRuntime().getUserDefinedReduction(DRD);
+ RValue Func = RValue::get(Reduction.first);
+ CodeGenFunction::OpaqueValueMapping Map(CGF, OVE, Func);
+ CGF.EmitIgnoredExpr(ReductionOp);
+ return;
+ }
+ CGF.EmitIgnoredExpr(ReductionOp);
+}
+
static llvm::Value *emitReductionFunction(CodeGenModule &CGM,
llvm::Type *ArgsType,
ArrayRef<const Expr *> Privates,
@@ -3667,13 +3697,14 @@ static llvm::Value *emitReductionFunction(CodeGenModule &CGM,
// Emit reduction for array section.
auto *LHSVar = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
auto *RHSVar = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
- EmitOMPAggregateReduction(CGF, (*IPriv)->getType(), LHSVar, RHSVar,
- [=](CodeGenFunction &CGF, const Expr *,
- const Expr *,
- const Expr *) { CGF.EmitIgnoredExpr(E); });
+ EmitOMPAggregateReduction(
+ CGF, (*IPriv)->getType(), LHSVar, RHSVar,
+ [=](CodeGenFunction &CGF, const Expr *, const Expr *, const Expr *) {
+ emitReductionCombiner(CGF, E);
+ });
} else
// Emit reduction for array subscript or single variable.
- CGF.EmitIgnoredExpr(E);
+ emitReductionCombiner(CGF, E);
++IPriv;
++ILHS;
++IRHS;
@@ -3740,9 +3771,9 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
EmitOMPAggregateReduction(
CGF, (*IPriv)->getType(), LHSVar, RHSVar,
[=](CodeGenFunction &CGF, const Expr *, const Expr *,
- const Expr *) { CGF.EmitIgnoredExpr(E); });
+ const Expr *) { emitReductionCombiner(CGF, E); });
} else
- CGF.EmitIgnoredExpr(E);
+ emitReductionCombiner(CGF, E);
++IPriv;
++ILHS;
++IRHS;
@@ -3857,10 +3888,10 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
EmitOMPAggregateReduction(
CGF, (*IPriv)->getType(), LHSVar, RHSVar,
[=](CodeGenFunction &CGF, const Expr *, const Expr *,
- const Expr *) { CGF.EmitIgnoredExpr(E); });
+ const Expr *) { emitReductionCombiner(CGF, E); });
} else
// Emit reduction for array subscript or single variable.
- CGF.EmitIgnoredExpr(E);
+ emitReductionCombiner(CGF, E);
++IPriv;
++ILHS;
++IRHS;
@@ -3962,7 +3993,8 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
const Expr *, const Expr *) {
emitCriticalRegion(
CGF, ".atomic_reduction",
- [E](CodeGenFunction &CGF) { CGF.EmitIgnoredExpr(E); }, Loc);
+ [=](CodeGenFunction &CGF) { emitReductionCombiner(CGF, E); },
+ Loc);
};
if ((*IPriv)->getType()->isArrayType()) {
auto *LHSVar = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h
index 97f08fc1e43..e9702170865 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.h
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.h
@@ -383,6 +383,9 @@ public:
/// Emit code for the specified user defined reduction construct.
virtual void emitUserDefinedReduction(CodeGenFunction *CGF,
const OMPDeclareReductionDecl *D);
+ /// Get combiner/initializer for the specified user-defined reduction, if any.
+ virtual std::pair<llvm::Function *, llvm::Function *>
+ getUserDefinedReduction(const OMPDeclareReductionDecl *D);
/// \brief Emits outlined function for the specified OpenMP parallel directive
/// \a D. This outlined function has type void(*)(kmp_int32 *ThreadID,
/// kmp_int32 BoundID, struct context_vars*).
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index eb62428eb38..30385cd8b92 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/DeclOpenMP.h"
+#include "llvm/IR/CallSite.h"
using namespace clang;
using namespace CodeGen;
@@ -310,12 +311,77 @@ void CodeGenFunction::EmitOMPAggregateAssign(
EmitBlock(DoneBB, /*IsFinished=*/true);
}
+/// Check if the combiner is a call to UDR combiner and if it is so return the
+/// UDR decl used for reduction.
+static const OMPDeclareReductionDecl *
+getReductionInit(const Expr *ReductionOp) {
+ if (auto *CE = dyn_cast<CallExpr>(ReductionOp))
+ if (auto *OVE = dyn_cast<OpaqueValueExpr>(CE->getCallee()))
+ if (auto *DRE =
+ dyn_cast<DeclRefExpr>(OVE->getSourceExpr()->IgnoreImpCasts()))
+ if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(DRE->getDecl()))
+ return DRD;
+ return nullptr;
+}
+
+static void emitInitWithReductionInitializer(CodeGenFunction &CGF,
+ const OMPDeclareReductionDecl *DRD,
+ const Expr *InitOp,
+ Address Private, Address Original,
+ QualType Ty) {
+ if (DRD->getInitializer()) {
+ std::pair<llvm::Function *, llvm::Function *> Reduction =
+ CGF.CGM.getOpenMPRuntime().getUserDefinedReduction(DRD);
+ auto *CE = cast<CallExpr>(InitOp);
+ auto *OVE = cast<OpaqueValueExpr>(CE->getCallee());
+ const Expr *LHS = CE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
+ const Expr *RHS = CE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
+ auto *LHSDRE = cast<DeclRefExpr>(cast<UnaryOperator>(LHS)->getSubExpr());
+ auto *RHSDRE = cast<DeclRefExpr>(cast<UnaryOperator>(RHS)->getSubExpr());
+ CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
+ PrivateScope.addPrivate(cast<VarDecl>(LHSDRE->getDecl()),
+ [=]() -> Address { return Private; });
+ PrivateScope.addPrivate(cast<VarDecl>(RHSDRE->getDecl()),
+ [=]() -> Address { return Original; });
+ (void)PrivateScope.Privatize();
+ RValue Func = RValue::get(Reduction.second);
+ CodeGenFunction::OpaqueValueMapping Map(CGF, OVE, Func);
+ CGF.EmitIgnoredExpr(InitOp);
+ } else {
+ llvm::Constant *Init = CGF.CGM.EmitNullConstant(Ty);
+ auto *GV = new llvm::GlobalVariable(
+ CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true,
+ llvm::GlobalValue::PrivateLinkage, Init, ".init");
+ LValue LV = CGF.MakeNaturalAlignAddrLValue(GV, Ty);
+ RValue InitRVal;
+ switch (CGF.getEvaluationKind(Ty)) {
+ case TEK_Scalar:
+ InitRVal = CGF.EmitLoadOfLValue(LV, SourceLocation());
+ break;
+ case TEK_Complex:
+ InitRVal =
+ RValue::getComplex(CGF.EmitLoadOfComplex(LV, SourceLocation()));
+ break;
+ case TEK_Aggregate:
+ InitRVal = RValue::getAggregate(LV.getAddress());
+ break;
+ }
+ OpaqueValueExpr OVE(SourceLocation(), Ty, VK_RValue);
+ CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, InitRVal);
+ CGF.EmitAnyExprToMem(&OVE, Private, Ty.getQualifiers(),
+ /*IsInitializer=*/false);
+ }
+}
+
/// \brief Emit initialization of arrays of complex types.
/// \param DestAddr Address of the array.
/// \param Type Type of array.
/// \param Init Initial expression of array.
+/// \param SrcAddr Address of the original array.
static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr,
- QualType Type, const Expr *Init) {
+ QualType Type, const Expr *Init,
+ Address SrcAddr = Address::invalid()) {
+ auto *DRD = getReductionInit(Init);
// Perform element-by-element initialization.
QualType ElementTy;
@@ -324,7 +390,13 @@ static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr,
auto NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, DestAddr);
DestAddr =
CGF.Builder.CreateElementBitCast(DestAddr, DestAddr.getElementType());
+ if (DRD)
+ SrcAddr =
+ CGF.Builder.CreateElementBitCast(SrcAddr, DestAddr.getElementType());
+ llvm::Value *SrcBegin = nullptr;
+ if (DRD)
+ SrcBegin = SrcAddr.getPointer();
auto DestBegin = DestAddr.getPointer();
// Cast from pointer to array type to pointer to single element.
auto DestEnd = CGF.Builder.CreateGEP(DestBegin, NumElements);
@@ -341,6 +413,16 @@ static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr,
CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy);
+ llvm::PHINode *SrcElementPHI = nullptr;
+ Address SrcElementCurrent = Address::invalid();
+ if (DRD) {
+ SrcElementPHI = CGF.Builder.CreatePHI(SrcBegin->getType(), 2,
+ "omp.arraycpy.srcElementPast");
+ SrcElementPHI->addIncoming(SrcBegin, EntryBB);
+ SrcElementCurrent =
+ Address(SrcElementPHI,
+ SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize));
+ }
llvm::PHINode *DestElementPHI = CGF.Builder.CreatePHI(
DestBegin->getType(), 2, "omp.arraycpy.destElementPast");
DestElementPHI->addIncoming(DestBegin, EntryBB);
@@ -351,8 +433,19 @@ static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr,
// Emit copy.
{
CodeGenFunction::RunCleanupsScope InitScope(CGF);
- CGF.EmitAnyExprToMem(Init, DestElementCurrent, ElementTy.getQualifiers(),
- /*IsInitializer=*/false);
+ if (DRD) {
+ emitInitWithReductionInitializer(CGF, DRD, Init, DestElementCurrent,
+ SrcElementCurrent, ElementTy);
+ } else
+ CGF.EmitAnyExprToMem(Init, DestElementCurrent, ElementTy.getQualifiers(),
+ /*IsInitializer=*/false);
+ }
+
+ if (DRD) {
+ // Shift the address forward by one element.
+ auto SrcElementNext = CGF.Builder.CreateConstGEP1_32(
+ SrcElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element");
+ SrcElementPHI->addIncoming(SrcElementNext, CGF.Builder.GetInsertBlock());
}
// Shift the address forward by one element.
@@ -752,10 +845,12 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
auto ILHS = C->lhs_exprs().begin();
auto IRHS = C->rhs_exprs().begin();
auto IPriv = C->privates().begin();
+ auto IRed = C->reduction_ops().begin();
for (auto IRef : C->varlists()) {
auto *LHSVD = cast<VarDecl>(cast<DeclRefExpr>(*ILHS)->getDecl());
auto *RHSVD = cast<VarDecl>(cast<DeclRefExpr>(*IRHS)->getDecl());
auto *PrivateVD = cast<VarDecl>(cast<DeclRefExpr>(*IPriv)->getDecl());
+ auto *DRD = getReductionInit(*IRed);
if (auto *OASE = dyn_cast<OMPArraySectionExpr>(IRef)) {
auto *Base = OASE->getBase()->IgnoreParenImpCasts();
while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
@@ -779,7 +874,7 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
// Emit reduction copy.
bool IsRegistered = PrivateScope.addPrivate(
OrigVD, [this, OrigVD, PrivateVD, BaseLValue, OASELValueLB,
- OASELValueUB, OriginalBaseLValue]() -> Address {
+ OASELValueUB, OriginalBaseLValue, DRD, IRed]() -> Address {
// Emit VarDecl with copy init for arrays.
// Get the address of the original variable captured in current
// captured region.
@@ -797,7 +892,9 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
auto Emission = EmitAutoVarAlloca(*PrivateVD);
auto Addr = Emission.getAllocatedAddress();
auto *Init = PrivateVD->getInit();
- EmitOMPAggregateInit(*this, Addr, PrivateVD->getType(), Init);
+ EmitOMPAggregateInit(*this, Addr, PrivateVD->getType(),
+ DRD ? *IRed : Init,
+ OASELValueLB.getAddress());
EmitAutoVarCleanups(Emission);
// Emit private VarDecl with reduction init.
auto *Offset = Builder.CreatePtrDiff(BaseLValue.getPointer(),
@@ -831,10 +928,17 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
// Emit reduction copy.
bool IsRegistered = PrivateScope.addPrivate(
OrigVD, [this, OrigVD, PrivateVD, BaseLValue, ASELValue,
- OriginalBaseLValue]() -> Address {
+ OriginalBaseLValue, DRD, IRed]() -> Address {
// Emit private VarDecl with reduction init.
- EmitDecl(*PrivateVD);
- auto Addr = GetAddrOfLocalVar(PrivateVD);
+ AutoVarEmission Emission = EmitAutoVarAlloca(*PrivateVD);
+ auto Addr = Emission.getAllocatedAddress();
+ if (DRD) {
+ emitInitWithReductionInitializer(*this, DRD, *IRed, Addr,
+ ASELValue.getAddress(),
+ ASELValue.getType());
+ } else
+ EmitAutoVarInit(Emission);
+ EmitAutoVarCleanups(Emission);
auto *Offset = Builder.CreatePtrDiff(BaseLValue.getPointer(),
ASELValue.getPointer());
auto *Ptr = Builder.CreateGEP(Addr.getPointer(), Offset);
@@ -859,11 +963,11 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
CapturedStmtInfo->lookup(OrigVD) != nullptr,
IRef->getType(), VK_LValue, IRef->getExprLoc());
Address OriginalAddr = EmitLValue(&DRE).getAddress();
- PrivateScope.addPrivate(LHSVD, [this, OriginalAddr,
+ PrivateScope.addPrivate(LHSVD, [this, &OriginalAddr,
LHSVD]() -> Address {
- return Builder.CreateElementBitCast(
- OriginalAddr, ConvertTypeForMem(LHSVD->getType()),
- "lhs.begin");
+ OriginalAddr = Builder.CreateElementBitCast(
+ OriginalAddr, ConvertTypeForMem(LHSVD->getType()), "lhs.begin");
+ return OriginalAddr;
});
bool IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address {
if (Type->isVariablyModifiedType()) {
@@ -879,7 +983,8 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
auto Emission = EmitAutoVarAlloca(*PrivateVD);
auto Addr = Emission.getAllocatedAddress();
auto *Init = PrivateVD->getInit();
- EmitOMPAggregateInit(*this, Addr, PrivateVD->getType(), Init);
+ EmitOMPAggregateInit(*this, Addr, PrivateVD->getType(),
+ DRD ? *IRed : Init, OriginalAddr);
EmitAutoVarCleanups(Emission);
return Emission.getAllocatedAddress();
});
@@ -894,18 +999,29 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
} else {
// Store the address of the original variable associated with the LHS
// implicit variable.
- PrivateScope.addPrivate(LHSVD, [this, OrigVD, IRef]() -> Address {
+ Address OriginalAddr = Address::invalid();
+ PrivateScope.addPrivate(LHSVD, [this, OrigVD, IRef,
+ &OriginalAddr]() -> Address {
DeclRefExpr DRE(const_cast<VarDecl *>(OrigVD),
CapturedStmtInfo->lookup(OrigVD) != nullptr,
IRef->getType(), VK_LValue, IRef->getExprLoc());
- return EmitLValue(&DRE).getAddress();
+ OriginalAddr = EmitLValue(&DRE).getAddress();
+ return OriginalAddr;
});
// Emit reduction copy.
- bool IsRegistered =
- PrivateScope.addPrivate(OrigVD, [this, PrivateVD]() -> Address {
+ bool IsRegistered = PrivateScope.addPrivate(
+ OrigVD, [this, PrivateVD, OriginalAddr, DRD, IRed]() -> Address {
// Emit private VarDecl with reduction init.
- EmitDecl(*PrivateVD);
- return GetAddrOfLocalVar(PrivateVD);
+ AutoVarEmission Emission = EmitAutoVarAlloca(*PrivateVD);
+ auto Addr = Emission.getAllocatedAddress();
+ if (DRD) {
+ emitInitWithReductionInitializer(*this, DRD, *IRed, Addr,
+ OriginalAddr,
+ PrivateVD->getType());
+ } else
+ EmitAutoVarInit(Emission);
+ EmitAutoVarCleanups(Emission);
+ return Addr;
});
assert(IsRegistered && "private var already registered as private");
// Silence the warning about unused variable.
@@ -918,6 +1034,7 @@ void CodeGenFunction::EmitOMPReductionClauseInit(
++ILHS;
++IRHS;
++IPriv;
+ ++IRed;
}
}
}
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 2d5afd6042d..7a924b4ce2b 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -109,9 +109,16 @@ static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) {
}
static DeclarationName parseOpenMPReductionId(Parser &P) {
- const Token Tok = P.getCurToken();
+ Token Tok = P.getCurToken();
Sema &Actions = P.getActions();
OverloadedOperatorKind OOK = OO_None;
+ // Allow to use 'operator' keyword for C++ operators
+ bool WithOperator = false;
+ if (Tok.is(tok::kw_operator)) {
+ P.ConsumeToken();
+ Tok = P.getCurToken();
+ WithOperator = true;
+ }
switch (Tok.getKind()) {
case tok::plus: // '+'
OOK = OO_Plus;
@@ -138,7 +145,8 @@ static DeclarationName parseOpenMPReductionId(Parser &P) {
OOK = OO_PipePipe;
break;
case tok::identifier: // identifier
- break;
+ if (!WithOperator)
+ break;
default:
P.Diag(Tok.getLocation(), diag::err_omp_expected_reduction_identifier);
P.SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end,
@@ -181,6 +189,8 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end))
return DeclGroupPtrTy();
+ IsCorrect = IsCorrect && !Name.isEmpty();
+
if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) {
Diag(Tok.getLocation(), diag::err_expected_type);
IsCorrect = false;
@@ -1209,9 +1219,10 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
// Handle reduction-identifier for reduction clause.
if (Kind == OMPC_reduction) {
ColonProtectionRAIIObject ColonRAII(*this);
- if (getLangOpts().CPlusPlus) {
- ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec, nullptr, false);
- }
+ if (getLangOpts().CPlusPlus)
+ ParseOptionalCXXScopeSpecifier(ReductionIdScopeSpec,
+ /*ObjectType=*/nullptr,
+ /*EnteringContext=*/false);
InvalidReductionId =
ParseReductionId(*this, ReductionIdScopeSpec, ReductionId);
if (InvalidReductionId) {
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 94eb6978ce9..56ab8ae3da9 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -15,6 +15,7 @@
#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclOpenMP.h"
@@ -7829,16 +7830,113 @@ public:
};
} // namespace
+template <typename T>
+static T filterLookupForUDR(SmallVectorImpl<UnresolvedSet<8>> &Lookups,
+ const llvm::function_ref<T(ValueDecl *)> &Gen) {
+ for (auto &Set : Lookups) {
+ for (auto *D : Set) {
+ if (auto Res = Gen(cast<ValueDecl>(D)))
+ return Res;
+ }
+ }
+ return T();
+}
+
+static ExprResult
+buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
+ Scope *S, CXXScopeSpec &ReductionIdScopeSpec,
+ const DeclarationNameInfo &ReductionId, QualType Ty,
+ CXXCastPath &BasePath, Expr *UnresolvedReduction) {
+ if (ReductionIdScopeSpec.isInvalid())
+ return ExprError();
+ SmallVector<UnresolvedSet<8>, 4> Lookups;
+ if (S) {
+ LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName);
+ Lookup.suppressDiagnostics();
+ while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec)) {
+ auto *D = Lookup.getRepresentativeDecl();
+ do {
+ S = S->getParent();
+ } while (S && !S->isDeclScope(D));
+ if (S)
+ S = S->getParent();
+ Lookups.push_back(UnresolvedSet<8>());
+ Lookups.back().append(Lookup.begin(), Lookup.end());
+ Lookup.clear();
+ }
+ } else if (auto *ULE =
+ cast_or_null<UnresolvedLookupExpr>(UnresolvedReduction)) {
+ Lookups.push_back(UnresolvedSet<8>());
+ Decl *PrevD = nullptr;
+ for(auto *D : ULE->decls()) {
+ if (D == PrevD)
+ Lookups.push_back(UnresolvedSet<8>());
+ else if (auto *DRD = cast<OMPDeclareReductionDecl>(D))
+ Lookups.back().addDecl(DRD);
+ PrevD = D;
+ }
+ }
+ if (Ty->isDependentType() || Ty->isInstantiationDependentType() ||
+ Ty->containsUnexpandedParameterPack() ||
+ filterLookupForUDR<bool>(Lookups, [](ValueDecl *D) -> bool {
+ return !D->isInvalidDecl() &&
+ (D->getType()->isDependentType() ||
+ D->getType()->isInstantiationDependentType() ||
+ D->getType()->containsUnexpandedParameterPack());
+ })) {
+ UnresolvedSet<8> ResSet;
+ for (auto &Set : Lookups) {
+ ResSet.append(Set.begin(), Set.end());
+ // The last item marks the end of all declarations at the specified scope.
+ ResSet.addDecl(Set[Set.size() - 1]);
+ }
+ return UnresolvedLookupExpr::Create(
+ SemaRef.Context, /*NamingClass=*/nullptr,
+ ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), ReductionId,
+ /*ADL=*/true, /*Overloaded=*/true, ResSet.begin(), ResSet.end());
+ }
+ if (auto *VD = filterLookupForUDR<ValueDecl *>(
+ Lookups, [&SemaRef, Ty](ValueDecl *D) -> ValueDecl * {
+ if (!D->isInvalidDecl() &&
+ SemaRef.Context.hasSameType(D->getType(), Ty))
+ return D;
+ return nullptr;
+ }))
+ return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc);
+ if (auto *VD = filterLookupForUDR<ValueDecl *>(
+ Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * {
+ if (!D->isInvalidDecl() &&
+ SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) &&
+ !Ty.isMoreQualifiedThan(D->getType()))
+ return D;
+ return nullptr;
+ })) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (SemaRef.IsDerivedFrom(Loc, Ty, VD->getType(), Paths)) {
+ if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType(
+ VD->getType().getUnqualifiedType()))) {
+ if (SemaRef.CheckBaseClassAccess(Loc, VD->getType(), Ty, Paths.front(),
+ /*DiagID=*/0) !=
+ Sema::AR_inaccessible) {
+ SemaRef.BuildBasePathArray(Paths, BasePath);
+ return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc);
+ }
+ }
+ }
+ }
+ if (ReductionIdScopeSpec.isSet()) {
+ SemaRef.Diag(Loc, diag::err_omp_not_resolved_reduction_identifier) << Range;
+ return ExprError();
+ }
+ return ExprEmpty();
+}
+
OMPClause *Sema::ActOnOpenMPReductionClause(
ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation ColonLoc, SourceLocation EndLoc,
- CXXScopeSpec &ReductionIdScopeSpec,
- const DeclarationNameInfo &ReductionId) {
- // TODO: Allow scope specification search when 'declare reduction' is
- // supported.
- assert(ReductionIdScopeSpec.isEmpty() &&
- "No support for scoped reduction identifiers yet.");
-
+ CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
auto DN = ReductionId.getName();
auto OOK = DN.getCXXOverloadedOperator();
BinaryOperatorKind BOK = BO_Comma;
@@ -7922,16 +8020,9 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
break;
}
SourceRange ReductionIdRange;
- if (ReductionIdScopeSpec.isValid()) {
+ if (ReductionIdScopeSpec.isValid())
ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc());
- }
ReductionIdRange.setEnd(ReductionId.getEndLoc());
- if (BOK == BO_Comma) {
- // Not allowed reduction identifier is found.
- Diag(ReductionId.getLocStart(), diag::err_omp_unknown_reduction_identifier)
- << ReductionIdRange;
- return nullptr;
- }
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> Privates;
@@ -7940,6 +8031,8 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
SmallVector<Expr *, 8> ReductionOps;
SmallVector<Decl *, 4> ExprCaptures;
SmallVector<Expr *, 4> ExprPostUpdates;
+ auto IR = UnresolvedReductions.begin(), ER = UnresolvedReductions.end();
+ bool FirstIter = true;
for (auto RefExpr : VarList) {
assert(RefExpr && "nullptr expr in OpenMP reduction clause.");
// OpenMP [2.1, C/C++]
@@ -7949,6 +8042,9 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// OpenMP [2.14.3.3, Restrictions, p.1]
// A variable that is part of another variable (as an array or
// structure element) cannot appear in a private clause.
+ if (!FirstIter && IR != ER)
+ ++IR;
+ FirstIter = false;
SourceLocation ELoc;
SourceRange ERange;
Expr *SimpleRefExpr = RefExpr;
@@ -7960,7 +8056,19 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
Privates.push_back(nullptr);
LHSs.push_back(nullptr);
RHSs.push_back(nullptr);
- ReductionOps.push_back(nullptr);
+ // Try to find 'declare reduction' corresponding construct before using
+ // builtin/overloaded operators.
+ QualType Type = Context.DependentTy;
+ CXXCastPath BasePath;
+ ExprResult DeclareReductionRef = buildDeclareReductionRef(
+ *this, ELoc, ERange, DSAStack->getCurScope(), ReductionIdScopeSpec,
+ ReductionId, Type, BasePath, IR == ER ? nullptr : *IR);
+ if (CurContext->isDependentContext() &&
+ (DeclareReductionRef.isUnset() ||
+ isa<UnresolvedLookupExpr>(DeclareReductionRef.get())))
+ ReductionOps.push_back(DeclareReductionRef.get());
+ else
+ ReductionOps.push_back(nullptr);
}
ValueDecl *D = Res.first;
if (!D)
@@ -8018,42 +8126,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
}
}
}
- // OpenMP [2.14.3.6, reduction clause, Restrictions]
- // The type of a list item that appears in a reduction clause must be valid
- // for the reduction-identifier. For a max or min reduction in C, the type
- // of the list item must be an allowed arithmetic data type: char, int,
- // float, double, or _Bool, possibly modified with long, short, signed, or
- // unsigned. For a max or min reduction in C++, the type of the list item
- // must be an allowed arithmetic data type: char, wchar_t, int, float,
- // double, or bool, possibly modified with long, short, signed, or unsigned.
- if ((BOK == BO_GT || BOK == BO_LT) &&
- !(Type->isScalarType() ||
- (getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
- Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
- << getLangOpts().CPlusPlus;
- if (!ASE && !OASE) {
- bool IsDecl = !VD ||
- VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(D->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << D;
- }
- continue;
- }
- if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) &&
- !getLangOpts().CPlusPlus && Type->isFloatingType()) {
- Diag(ELoc, diag::err_omp_clause_floating_type_arg);
- if (!ASE && !OASE) {
- bool IsDecl = !VD ||
- VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(D->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << D;
- }
- continue;
- }
+
// OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
// Variables with the predetermined data-sharing attributes may not be
@@ -8097,6 +8170,71 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
}
}
+ // Try to find 'declare reduction' corresponding construct before using
+ // builtin/overloaded operators.
+ CXXCastPath BasePath;
+ ExprResult DeclareReductionRef = buildDeclareReductionRef(
+ *this, ELoc, ERange, DSAStack->getCurScope(), ReductionIdScopeSpec,
+ ReductionId, Type, BasePath, IR == ER ? nullptr : *IR);
+ if (DeclareReductionRef.isInvalid())
+ continue;
+ if (CurContext->isDependentContext() &&
+ (DeclareReductionRef.isUnset() ||
+ isa<UnresolvedLookupExpr>(DeclareReductionRef.get()))) {
+ Vars.push_back(RefExpr);
+ Privates.push_back(nullptr);
+ LHSs.push_back(nullptr);
+ RHSs.push_back(nullptr);
+ ReductionOps.push_back(DeclareReductionRef.get());
+ continue;
+ }
+ if (BOK == BO_Comma && DeclareReductionRef.isUnset()) {
+ // Not allowed reduction identifier is found.
+ Diag(ReductionId.getLocStart(),
+ diag::err_omp_unknown_reduction_identifier)
+ << Type << ReductionIdRange;
+ continue;
+ }
+
+ // OpenMP [2.14.3.6, reduction clause, Restrictions]
+ // The type of a list item that appears in a reduction clause must be valid
+ // for the reduction-identifier. For a max or min reduction in C, the type
+ // of the list item must be an allowed arithmetic data type: char, int,
+ // float, double, or _Bool, possibly modified with long, short, signed, or
+ // unsigned. For a max or min reduction in C++, the type of the list item
+ // must be an allowed arithmetic data type: char, wchar_t, int, float,
+ // double, or bool, possibly modified with long, short, signed, or unsigned.
+ if (DeclareReductionRef.isUnset()) {
+ if ((BOK == BO_GT || BOK == BO_LT) &&
+ !(Type->isScalarType() ||
+ (getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
+ Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
+ << getLangOpts().CPlusPlus;
+ if (!ASE && !OASE) {
+ bool IsDecl = !VD ||
+ VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << D;
+ }
+ continue;
+ }
+ if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) &&
+ !getLangOpts().CPlusPlus && Type->isFloatingType()) {
+ Diag(ELoc, diag::err_omp_clause_floating_type_arg);
+ if (!ASE && !OASE) {
+ bool IsDecl = !VD ||
+ VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << D;
+ }
+ continue;
+ }
+ }
+
Type = Type.getNonLValueExprType(Context).getUnqualifiedType();
auto *LHSVD = buildVarDecl(*this, ELoc, Type, ".reduction.lhs",
D->hasAttrs() ? &D->getAttrs() : nullptr);
@@ -8123,113 +8261,127 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
D->hasAttrs() ? &D->getAttrs() : nullptr);
// Add initializer for private variable.
Expr *Init = nullptr;
- switch (BOK) {
- case BO_Add:
- case BO_Xor:
- case BO_Or:
- case BO_LOr:
- // '+', '-', '^', '|', '||' reduction ops - initializer is '0'.
- if (Type->isScalarType() || Type->isAnyComplexType())
- Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get();
- break;
- case BO_Mul:
- case BO_LAnd:
- if (Type->isScalarType() || Type->isAnyComplexType()) {
- // '*' and '&&' reduction ops - initializer is '1'.
- Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get();
- }
- break;
- case BO_And: {
- // '&' reduction op - initializer is '~0'.
- QualType OrigType = Type;
- if (auto *ComplexTy = OrigType->getAs<ComplexType>())
- Type = ComplexTy->getElementType();
- if (Type->isRealFloatingType()) {
- llvm::APFloat InitValue =
- llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type),
- /*isIEEE=*/true);
- Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
- Type, ELoc);
- } else if (Type->isScalarType()) {
- auto Size = Context.getTypeSize(Type);
- QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0);
- llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size);
- Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
+ auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc);
+ auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc);
+ if (DeclareReductionRef.isUsable()) {
+ auto *DRDRef = DeclareReductionRef.getAs<DeclRefExpr>();
+ auto *DRD = cast<OMPDeclareReductionDecl>(DRDRef->getDecl());
+ if (DRD->getInitializer()) {
+ Init = DRDRef;
+ RHSVD->setInit(DRDRef);
+ RHSVD->setInitStyle(VarDecl::CallInit);
}
- if (Init && OrigType->isAnyComplexType()) {
- // Init = 0xFFFF + 0xFFFFi;
- auto *Im = new (Context) ImaginaryLiteral(Init, OrigType);
- Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get();
+ } else {
+ switch (BOK) {
+ case BO_Add:
+ case BO_Xor:
+ case BO_Or:
+ case BO_LOr:
+ // '+', '-', '^', '|', '||' reduction ops - initializer is '0'.
+ if (Type->isScalarType() || Type->isAnyComplexType())
+ Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get();
+ break;
+ case BO_Mul:
+ case BO_LAnd:
+ if (Type->isScalarType() || Type->isAnyComplexType()) {
+ // '*' and '&&' reduction ops - initializer is '1'.
+ Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get();
+ }
+ break;
+ case BO_And: {
+ // '&' reduction op - initializer is '~0'.
+ QualType OrigType = Type;
+ if (auto *ComplexTy = OrigType->getAs<ComplexType>())
+ Type = ComplexTy->getElementType();
+ if (Type->isRealFloatingType()) {
+ llvm::APFloat InitValue =
+ llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type),
+ /*isIEEE=*/true);
+ Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
+ Type, ELoc);
+ } else if (Type->isScalarType()) {
+ auto Size = Context.getTypeSize(Type);
+ QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0);
+ llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size);
+ Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
+ }
+ if (Init && OrigType->isAnyComplexType()) {
+ // Init = 0xFFFF + 0xFFFFi;
+ auto *Im = new (Context) ImaginaryLiteral(Init, OrigType);
+ Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get();
+ }
+ Type = OrigType;
+ break;
}
- Type = OrigType;
- break;
- }
- case BO_LT:
- case BO_GT: {
- // 'min' reduction op - initializer is 'Largest representable number in
- // the reduction list item type'.
- // 'max' reduction op - initializer is 'Least representable number in
- // the reduction list item type'.
- if (Type->isIntegerType() || Type->isPointerType()) {
- bool IsSigned = Type->hasSignedIntegerRepresentation();
- auto Size = Context.getTypeSize(Type);
- QualType IntTy =
- Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned);
- llvm::APInt InitValue =
- (BOK != BO_LT)
- ? IsSigned ? llvm::APInt::getSignedMinValue(Size)
- : llvm::APInt::getMinValue(Size)
- : IsSigned ? llvm::APInt::getSignedMaxValue(Size)
- : llvm::APInt::getMaxValue(Size);
- Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
- if (Type->isPointerType()) {
- // Cast to pointer type.
- auto CastExpr = BuildCStyleCastExpr(
- SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc),
- SourceLocation(), Init);
- if (CastExpr.isInvalid())
- continue;
- Init = CastExpr.get();
+ case BO_LT:
+ case BO_GT: {
+ // 'min' reduction op - initializer is 'Largest representable number in
+ // the reduction list item type'.
+ // 'max' reduction op - initializer is 'Least representable number in
+ // the reduction list item type'.
+ if (Type->isIntegerType() || Type->isPointerType()) {
+ bool IsSigned = Type->hasSignedIntegerRepresentation();
+ auto Size = Context.getTypeSize(Type);
+ QualType IntTy =
+ Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned);
+ llvm::APInt InitValue =
+ (BOK != BO_LT)
+ ? IsSigned ? llvm::APInt::getSignedMinValue(Size)
+ : llvm::APInt::getMinValue(Size)
+ : IsSigned ? llvm::APInt::getSignedMaxValue(Size)
+ : llvm::APInt::getMaxValue(Size);
+ Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
+ if (Type->isPointerType()) {
+ // Cast to pointer type.
+ auto CastExpr = BuildCStyleCastExpr(
+ SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc),
+ SourceLocation(), Init);
+ if (CastExpr.isInvalid())
+ continue;
+ Init = CastExpr.get();
+ }
+ } else if (Type->isRealFloatingType()) {
+ llvm::APFloat InitValue = llvm::APFloat::getLargest(
+ Context.getFloatTypeSemantics(Type), BOK != BO_LT);
+ Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
+ Type, ELoc);
}
- } else if (Type->isRealFloatingType()) {
- llvm::APFloat InitValue = llvm::APFloat::getLargest(
- Context.getFloatTypeSemantics(Type), BOK != BO_LT);
- Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
- Type, ELoc);
+ break;
+ }
+ case BO_PtrMemD:
+ case BO_PtrMemI:
+ case BO_MulAssign:
+ case BO_Div:
+ case BO_Rem:
+ case BO_Sub:
+ case BO_Shl:
+ case BO_Shr:
+ case BO_LE:
+ case BO_GE:
+ case BO_EQ:
+ case BO_NE:
+ case BO_AndAssign:
+ case BO_XorAssign:
+ case BO_OrAssign:
+ case BO_Assign:
+ case BO_AddAssign:
+ case BO_SubAssign:
+ case BO_DivAssign:
+ case BO_RemAssign:
+ case BO_ShlAssign:
+ case BO_ShrAssign:
+ case BO_Comma:
+ llvm_unreachable("Unexpected reduction operation");
}
- break;
}
- case BO_PtrMemD:
- case BO_PtrMemI:
- case BO_MulAssign:
- case BO_Div:
- case BO_Rem:
- case BO_Sub:
- case BO_Shl:
- case BO_Shr:
- case BO_LE:
- case BO_GE:
- case BO_EQ:
- case BO_NE:
- case BO_AndAssign:
- case BO_XorAssign:
- case BO_OrAssign:
- case BO_Assign:
- case BO_AddAssign:
- case BO_SubAssign:
- case BO_DivAssign:
- case BO_RemAssign:
- case BO_ShlAssign:
- case BO_ShrAssign:
- case BO_Comma:
- llvm_unreachable("Unexpected reduction operation");
- }
- if (Init) {
+ if (Init && DeclareReductionRef.isUnset()) {
AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false,
/*TypeMayContainAuto=*/false);
- } else
+ } else if (!Init)
ActOnUninitializedDecl(RHSVD, /*TypeMayContainAuto=*/false);
- if (!RHSVD->hasInit()) {
+ if (RHSVD->isInvalidDecl())
+ continue;
+ if (!RHSVD->hasInit() && DeclareReductionRef.isUnset()) {
Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type
<< ReductionIdRange;
bool IsDecl =
@@ -8244,29 +8396,53 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// codegen.
PrivateVD->setInit(RHSVD->getInit());
PrivateVD->setInitStyle(RHSVD->getInitStyle());
- auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc);
- auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc);
auto *PrivateDRE = buildDeclRefExpr(*this, PrivateVD, PrivateTy, ELoc);
- ExprResult ReductionOp =
- BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK,
- LHSDRE, RHSDRE);
- if (ReductionOp.isUsable()) {
- if (BOK != BO_LT && BOK != BO_GT) {
- ReductionOp =
- BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
- BO_Assign, LHSDRE, ReductionOp.get());
- } else {
- auto *ConditionalOp = new (Context) ConditionalOperator(
- ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(),
- RHSDRE, Type, VK_LValue, OK_Ordinary);
- ReductionOp =
- BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
- BO_Assign, LHSDRE, ConditionalOp);
+ ExprResult ReductionOp;
+ if (DeclareReductionRef.isUsable()) {
+ QualType RedTy = DeclareReductionRef.get()->getType();
+ QualType PtrRedTy = Context.getPointerType(RedTy);
+ ExprResult LHS = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, LHSDRE);
+ ExprResult RHS = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RHSDRE);
+ if (!BasePath.empty()) {
+ LHS = DefaultLvalueConversion(LHS.get());
+ RHS = DefaultLvalueConversion(RHS.get());
+ LHS = ImplicitCastExpr::Create(Context, PtrRedTy,
+ CK_UncheckedDerivedToBase, LHS.get(),
+ &BasePath, LHS.get()->getValueKind());
+ RHS = ImplicitCastExpr::Create(Context, PtrRedTy,
+ CK_UncheckedDerivedToBase, RHS.get(),
+ &BasePath, RHS.get()->getValueKind());
}
- ReductionOp = ActOnFinishFullExpr(ReductionOp.get());
+ FunctionProtoType::ExtProtoInfo EPI;
+ QualType Params[] = {PtrRedTy, PtrRedTy};
+ QualType FnTy = Context.getFunctionType(Context.VoidTy, Params, EPI);
+ auto *OVE = new (Context) OpaqueValueExpr(
+ ELoc, Context.getPointerType(FnTy), VK_RValue, OK_Ordinary,
+ DefaultLvalueConversion(DeclareReductionRef.get()).get());
+ Expr *Args[] = {LHS.get(), RHS.get()};
+ ReductionOp = new (Context)
+ CallExpr(Context, OVE, Args, Context.VoidTy, VK_RValue, ELoc);
+ } else {
+ ReductionOp = BuildBinOp(DSAStack->getCurScope(),
+ ReductionId.getLocStart(), BOK, LHSDRE, RHSDRE);
+ if (ReductionOp.isUsable()) {
+ if (BOK != BO_LT && BOK != BO_GT) {
+ ReductionOp =
+ BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
+ BO_Assign, LHSDRE, ReductionOp.get());
+ } else {
+ auto *ConditionalOp = new (Context) ConditionalOperator(
+ ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(),
+ RHSDRE, Type, VK_LValue, OK_Ordinary);
+ ReductionOp =
+ BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
+ BO_Assign, LHSDRE, ConditionalOp);
+ }
+ ReductionOp = ActOnFinishFullExpr(ReductionOp.get());
+ }
+ if (ReductionOp.isInvalid())
+ continue;
}
- if (ReductionOp.isInvalid())
- continue;
DeclRefExpr *Ref = nullptr;
Expr *VarsExpr = RefExpr->IgnoreParens();
@@ -9874,10 +10050,14 @@ void Sema::ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D) {
PushExpressionEvaluationContext(PotentiallyEvaluated);
QualType ReductionType = DRD->getType();
- // Create 'T omp_in;' implicit param.
+ // Create 'T* omp_parm;T omp_in;'. All references to 'omp_in' will
+ // be replaced by '*omp_parm' during codegen. This required because 'omp_in'
+ // 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_in;' variable.
auto *OmpInParm =
- ImplicitParamDecl::Create(Context, DRD, D->getLocation(),
- &Context.Idents.get("omp_in"), ReductionType);
+ buildVarDecl(*this, D->getLocation(), ReductionType, "omp_in");
// 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
@@ -9924,10 +10104,6 @@ void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) {
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
@@ -9936,6 +10112,14 @@ void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) {
// Create 'T omp_priv;' variable.
auto *OmpPrivParm =
buildVarDecl(*this, D->getLocation(), ReductionType, "omp_priv");
+ // Create 'T* omp_parm;T omp_orig;'. All references to 'omp_orig' will
+ // be replaced by '*omp_parm' during codegen. This required because 'omp_orig'
+ // 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_orig;' variable.
+ auto *OmpOrigParm =
+ buildVarDecl(*this, D->getLocation(), ReductionType, "omp_orig");
if (S != nullptr) {
PushOnScopeChains(OmpPrivParm, S);
PushOnScopeChains(OmpOrigParm, S);
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index ffffb7757c2..6f09c0f5355 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1561,10 +1561,11 @@ public:
SourceLocation ColonLoc,
SourceLocation EndLoc,
CXXScopeSpec &ReductionIdScopeSpec,
- const DeclarationNameInfo &ReductionId) {
+ const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
return getSema().ActOnOpenMPReductionClause(
VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec,
- ReductionId);
+ ReductionId, UnresolvedReductions);
}
/// \brief Build a new OpenMP 'linear' clause.
@@ -7791,9 +7792,31 @@ TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause *C) {
if (!NameInfo.getName())
return nullptr;
}
+ // Build a list of all UDR decls with the same names ranged by the Scopes.
+ // The Scope boundary is a duplication of the previous decl.
+ llvm::SmallVector<Expr *, 16> UnresolvedReductions;
+ for (auto *E : C->reduction_ops()) {
+ // Transform all the decls.
+ if (E) {
+ auto *ULE = cast<UnresolvedLookupExpr>(E);
+ UnresolvedSet<8> Decls;
+ for (auto *D : ULE->decls()) {
+ NamedDecl *InstD =
+ cast<NamedDecl>(getDerived().TransformDecl(E->getExprLoc(), D));
+ Decls.addDecl(InstD, InstD->getAccess());
+ }
+ UnresolvedReductions.push_back(
+ UnresolvedLookupExpr::Create(
+ SemaRef.Context, /*NamingClass=*/nullptr,
+ ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context),
+ NameInfo, /*ADL=*/true, ULE->isOverloaded(),
+ Decls.begin(), Decls.end()));
+ } else
+ UnresolvedReductions.push_back(nullptr);
+ }
return getDerived().RebuildOMPReductionClause(
Vars, C->getLocStart(), C->getLParenLoc(), C->getColonLoc(),
- C->getLocEnd(), ReductionIdScopeSpec, NameInfo);
+ C->getLocEnd(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions);
}
template <typename Derived>
OpenPOWER on IntegriCloud