diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/CodeGen/CGOpenMPRuntime.cpp | 58 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGOpenMPRuntime.h | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGStmtOpenMP.cpp | 155 | ||||
-rw-r--r-- | clang/lib/Parse/ParseOpenMP.cpp | 21 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOpenMP.cpp | 540 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 29 |
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> |