From eefab7c779cb29ec3855d9d75effdb28e75e763f Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Wed, 2 Mar 2016 04:57:40 +0000 Subject: [PATCH] [OPENMP 4.5] Codegen for data members in 'reduction' clause. OpenMP 4.5 allows to privatize non-static data members of current class in non-static member functions. Patch supports codegen for non-static data members in 'reduction' clauses. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@262460 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/OpenMPClause.h | 12 +- include/clang/AST/RecursiveASTVisitor.h | 2 + include/clang/Sema/Sema.h | 2 +- lib/AST/OpenMPClause.cpp | 11 +- lib/AST/StmtProfile.cpp | 2 + lib/CodeGen/CGStmtOpenMP.cpp | 41 +++++ lib/Sema/SemaExprMember.cpp | 2 +- lib/Sema/SemaOpenMP.cpp | 77 +++++++-- lib/Serialization/ASTReaderStmt.cpp | 2 + lib/Serialization/ASTWriterStmt.cpp | 2 + test/OpenMP/for_lastprivate_codegen.cpp | 4 +- test/OpenMP/parallel_reduction_codegen.cpp | 184 ++++++++++++++++++++- tools/libclang/CIndex.cpp | 2 + 13 files changed, 315 insertions(+), 28 deletions(-) diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h index 17efb9468c..6b8e32bd4c 100644 --- a/include/clang/AST/OpenMPClause.h +++ b/include/clang/AST/OpenMPClause.h @@ -1665,6 +1665,8 @@ public: /// class OMPReductionClause final : public OMPVarListClause, + public OMPClauseWithPreInit, + public OMPClauseWithPostUpdate, private llvm::TrailingObjects { friend TrailingObjects; friend OMPVarListClause; @@ -1692,6 +1694,7 @@ class OMPReductionClause final const DeclarationNameInfo &NameInfo) : OMPVarListClause(OMPC_reduction, StartLoc, LParenLoc, EndLoc, N), + OMPClauseWithPreInit(this), OMPClauseWithPostUpdate(this), ColonLoc(ColonLoc), QualifierLoc(QualifierLoc), NameInfo(NameInfo) {} /// \brief Build an empty clause. @@ -1702,7 +1705,8 @@ class OMPReductionClause final : OMPVarListClause(OMPC_reduction, SourceLocation(), SourceLocation(), SourceLocation(), N), - ColonLoc(), QualifierLoc(), NameInfo() {} + OMPClauseWithPreInit(this), OMPClauseWithPostUpdate(this), ColonLoc(), + QualifierLoc(), NameInfo() {} /// \brief Sets location of ':' symbol in clause. void setColonLoc(SourceLocation CL) { ColonLoc = CL; } @@ -1795,6 +1799,10 @@ public: /// \endcode /// Required for proper codegen of final reduction operation performed by the /// reduction clause. + /// \param PreInit Statement that must be executed before entering the OpenMP + /// region with this clause. + /// \param PostUpdate Expression that must be executed after exit from the + /// OpenMP region with this clause. /// static OMPReductionClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -1802,7 +1810,7 @@ public: NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, ArrayRef Privates, ArrayRef LHSExprs, ArrayRef RHSExprs, - ArrayRef ReductionOps); + ArrayRef ReductionOps, Stmt *PreInit, Expr *PostUpdate); /// \brief Creates an empty clause with the place for \a N variables. /// /// \param C AST context. diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 07bd0e1fcf..58850f5594 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -2766,6 +2766,8 @@ RecursiveASTVisitor::VisitOMPReductionClause(OMPReductionClause *C) { TRY_TO(TraverseNestedNameSpecifierLoc(C->getQualifierLoc())); TRY_TO(TraverseDeclarationNameInfo(C->getNameInfo())); TRY_TO(VisitOMPClauseList(C)); + TRY_TO(VisitOMPClauseWithPreInit(C)); + TRY_TO(VisitOMPClauseWithPostUpdate(C)); for (auto *E : C->privates()) { TRY_TO(TraverseStmt(E)); } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 563eea0eb1..ec1ade4926 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -7834,7 +7834,7 @@ public: /// constructs. VarDecl *IsOpenMPCapturedDecl(ValueDecl *D); ExprResult getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, - ExprObjectKind OK); + ExprObjectKind OK, SourceLocation Loc); /// \brief Check if the specified variable is used in 'private' clause. /// \param Level Relative level of nested OpenMP construct for that the check diff --git a/lib/AST/OpenMPClause.cpp b/lib/AST/OpenMPClause.cpp index 0a2b87410b..3c0952be55 100644 --- a/lib/AST/OpenMPClause.cpp +++ b/lib/AST/OpenMPClause.cpp @@ -44,6 +44,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { return static_cast(C); case OMPC_lastprivate: return static_cast(C); + case OMPC_reduction: + return static_cast(C); case OMPC_default: case OMPC_proc_bind: case OMPC_if: @@ -54,7 +56,6 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_collapse: case OMPC_private: case OMPC_shared: - case OMPC_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: @@ -99,6 +100,8 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) switch (C->getClauseKind()) { case OMPC_lastprivate: return static_cast(C); + case OMPC_reduction: + return static_cast(C); case OMPC_schedule: case OMPC_dist_schedule: case OMPC_firstprivate: @@ -112,7 +115,6 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) case OMPC_collapse: case OMPC_private: case OMPC_shared: - case OMPC_reduction: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: @@ -463,7 +465,8 @@ OMPReductionClause *OMPReductionClause::Create( SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef VL, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, ArrayRef Privates, ArrayRef LHSExprs, - ArrayRef RHSExprs, ArrayRef ReductionOps) { + ArrayRef RHSExprs, ArrayRef ReductionOps, Stmt *PreInit, + Expr *PostUpdate) { void *Mem = C.Allocate(totalSizeToAlloc(5 * VL.size())); OMPReductionClause *Clause = new (Mem) OMPReductionClause( StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo); @@ -472,6 +475,8 @@ OMPReductionClause *OMPReductionClause::Create( Clause->setLHSExprs(LHSExprs); Clause->setRHSExprs(RHSExprs); Clause->setReductionOps(ReductionOps); + Clause->setPreInitStmt(PreInit); + Clause->setPostUpdateExpr(PostUpdate); return Clause; } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 4686483871..c0da73d296 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -399,6 +399,8 @@ void OMPClauseProfiler::VisitOMPReductionClause( C->getQualifierLoc().getNestedNameSpecifier()); Profiler->VisitName(C->getNameInfo().getName()); VisitOMPClauseList(C); + VistOMPClauseWithPreInit(C); + VistOMPClauseWithPostUpdate(C); for (auto *E : C->privates()) { Profiler->VisitStmt(E); } diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index 457d21e3dc..90d6a829e1 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -943,6 +943,31 @@ void CodeGenFunction::EmitOMPReductionClauseFinal( } } +static void emitPostUpdateForReductionClause( + CodeGenFunction &CGF, const OMPExecutableDirective &D, + const llvm::function_ref &CondGen) { + if (!CGF.HaveInsertPoint()) + return; + llvm::BasicBlock *DoneBB = nullptr; + for (const auto *C : D.getClausesOfKind()) { + if (auto *PostUpdate = C->getPostUpdateExpr()) { + if (!DoneBB) { + if (auto *Cond = CondGen(CGF)) { + // If the first post-update expression is found, emit conditional + // block if it was requested. + auto *ThenBB = CGF.createBasicBlock(".omp.reduction.pu"); + DoneBB = CGF.createBasicBlock(".omp.reduction.pu.done"); + CGF.Builder.CreateCondBr(Cond, ThenBB, DoneBB); + CGF.EmitBlock(ThenBB); + } + } + CGF.EmitIgnoredExpr(PostUpdate); + } + } + if (DoneBB) + CGF.EmitBlock(DoneBB, /*IsFinished=*/true); +} + static void emitCommonOMPParallelDirective(CodeGenFunction &CGF, const OMPExecutableDirective &S, OpenMPDirectiveKind InnermostKind, @@ -998,6 +1023,8 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { CGF.EmitOMPReductionClauseFinal(S); }; emitCommonOMPParallelDirective(*this, S, OMPD_parallel, CodeGen); + emitPostUpdateForReductionClause( + *this, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); } void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D, @@ -1346,6 +1373,8 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { CGF.EmitOMPLastprivateClauseFinal(S); } CGF.EmitOMPReductionClauseFinal(S); + emitPostUpdateForReductionClause( + CGF, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); } CGF.EmitOMPSimdFinal(S); // Emit: if (PreCond) - end. @@ -1669,6 +1698,12 @@ bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) { IL.getAddress(), Chunk); } EmitOMPReductionClauseFinal(S); + // Emit post-update of the reduction variables if IsLastIter != 0. + emitPostUpdateForReductionClause( + *this, S, [&](CodeGenFunction &CGF) -> llvm::Value * { + return CGF.Builder.CreateIsNotNull( + CGF.EmitLoadOfScalar(IL, S.getLocStart())); + }); // Emit final copy of the lastprivate variables if IsLastIter != 0. if (HasLastprivateClause) EmitOMPLastprivateClauseFinal( @@ -1827,6 +1862,12 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { // Tell the runtime we are done. CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocStart()); CGF.EmitOMPReductionClauseFinal(S); + // Emit post-update of the reduction variables if IsLastIter != 0. + emitPostUpdateForReductionClause( + CGF, S, [&](CodeGenFunction &CGF) -> llvm::Value * { + return CGF.Builder.CreateIsNotNull( + CGF.EmitLoadOfScalar(IL, S.getLocStart())); + }); // Emit final copy of the lastprivate variables if IsLastIter != 0. if (HasLastprivates) diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index dfe63a86d2..0ce3974e51 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -1794,7 +1794,7 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, if (S.getLangOpts().OpenMP && IsArrow && isa(Base.get()->IgnoreParenImpCasts())) { if (auto *PrivateCopy = S.IsOpenMPCapturedDecl(Field)) - return S.getOpenMPCapturedExpr(PrivateCopy, VK, OK); + return S.getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc); } return ME; } diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index e115a2ffd4..86ad66f4a6 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -1705,7 +1705,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { } static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, - Expr *CaptureExpr) { + Expr *CaptureExpr, bool WithInit) { ASTContext &C = S.getASTContext(); Expr *Init = CaptureExpr->IgnoreImpCasts(); QualType Ty = Init->getType(); @@ -1720,27 +1720,33 @@ static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, return nullptr; Init = Res.get(); } + WithInit = true; } auto *CED = OMPCapturedExprDecl::Create(C, S.CurContext, Id, Ty); S.CurContext->addHiddenDecl(CED); - S.AddInitializerToDecl(CED, Init, /*DirectInit=*/false, - /*TypeMayContainAuto=*/true); + if (WithInit) + S.AddInitializerToDecl(CED, Init, /*DirectInit=*/false, + /*TypeMayContainAuto=*/true); + else + S.ActOnUninitializedDecl(CED, /*TypeMayContainAuto=*/true); return CED; } -static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr) { +static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr, + bool WithInit) { OMPCapturedExprDecl *CD; if (auto *VD = S.IsOpenMPCapturedDecl(D)) CD = cast(VD); else - CD = buildCaptureDecl(S, D->getIdentifier(), CaptureExpr); + CD = buildCaptureDecl(S, D->getIdentifier(), CaptureExpr, WithInit); return buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(), SourceLocation()); } static DeclRefExpr *buildCapture(Sema &S, Expr *CaptureExpr) { - auto *CD = buildCaptureDecl( - S, &S.getASTContext().Idents.get(".capture_expr."), CaptureExpr); + auto *CD = + buildCaptureDecl(S, &S.getASTContext().Idents.get(".capture_expr."), + CaptureExpr, /*WithInit=*/true); return buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(), SourceLocation()); } @@ -7077,8 +7083,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( } ExprResult Sema::getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, - ExprObjectKind OK) { - SourceLocation Loc = Capture->getInit()->getExprLoc(); + ExprObjectKind OK, SourceLocation Loc) { ExprResult Res = BuildDeclRefExpr( Capture, Capture->getType().getNonReferenceType(), VK_LValue, Loc); if (!Res.isUsable()) @@ -7236,7 +7241,7 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, DeclRefExpr *Ref = nullptr; if (!VD) - Ref = buildCapture(*this, D, SimpleRefExpr); + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref); Vars.push_back(VD ? RefExpr->IgnoreParens() : Ref); PrivateCopies.push_back(VDPrivateRefExpr); @@ -7520,7 +7525,7 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef VarList, if (TopDVar.CKind == OMPC_lastprivate) Ref = TopDVar.PrivateCopy; else { - Ref = buildCapture(*this, D, SimpleRefExpr); + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); if (!IsOpenMPCapturedDecl(D)) ExprCaptures.push_back(Ref->getDecl()); } @@ -7665,13 +7670,13 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef VarList, if (TopDVar.CKind == OMPC_firstprivate) Ref = TopDVar.PrivateCopy; else { - Ref = buildCapture(*this, D, SimpleRefExpr); + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); if (!IsOpenMPCapturedDecl(D)) ExprCaptures.push_back(Ref->getDecl()); } if (TopDVar.CKind == OMPC_firstprivate || (!IsOpenMPCapturedDecl(D) && - !Ref->getDecl()->getType()->isReferenceType())) { + !cast(Ref->getDecl())->getInit())) { ExprResult RefRes = DefaultLvalueConversion(Ref); if (!RefRes.isUsable()) continue; @@ -7754,7 +7759,7 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef VarList, DeclRefExpr *Ref = nullptr; if (!VD) - Ref = buildCapture(*this, D, SimpleRefExpr); + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_shared, Ref); Vars.push_back(VD ? RefExpr->IgnoreParens() : Ref); } @@ -7811,7 +7816,7 @@ public: ExprResult TransformMemberExpr(MemberExpr *E) { if (isa(E->getBase()->IgnoreParenImpCasts()) && E->getMemberDecl() == Field) { - CapturedExpr = buildCapture(SemaRef, Field, E); + CapturedExpr = buildCapture(SemaRef, Field, E, /*WithInit=*/false); return CapturedExpr; } return BaseTransform::TransformMemberExpr(E); @@ -7929,6 +7934,8 @@ OMPClause *Sema::ActOnOpenMPReductionClause( SmallVector LHSs; SmallVector RHSs; SmallVector ReductionOps; + SmallVector ExprCaptures; + SmallVector ExprPostUpdates; for (auto RefExpr : VarList) { assert(RefExpr && "nullptr expr in OpenMP reduction clause."); // OpenMP [2.1, C/C++] @@ -8265,8 +8272,24 @@ OMPClause *Sema::ActOnOpenMPReductionClause( VarsExpr = RebuildToCapture.TransformExpr(RefExpr->IgnoreParens()).get(); Ref = RebuildToCapture.getCapturedExpr(); - } else - VarsExpr = Ref = buildCapture(*this, D, SimpleRefExpr); + } else { + VarsExpr = Ref = + buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); + if (!IsOpenMPCapturedDecl(D)) { + ExprCaptures.push_back(Ref->getDecl()); + if (!cast(Ref->getDecl())->getInit()) { + ExprResult RefRes = DefaultLvalueConversion(Ref); + if (!RefRes.isUsable()) + continue; + ExprResult PostUpdateRes = + BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, + SimpleRefExpr, RefRes.get()); + if (!PostUpdateRes.isUsable()) + continue; + ExprPostUpdates.push_back(PostUpdateRes.get()); + } + } + } } DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref); Vars.push_back(VarsExpr); @@ -8278,11 +8301,29 @@ OMPClause *Sema::ActOnOpenMPReductionClause( if (Vars.empty()) return nullptr; + Stmt *PreInit = nullptr; + if (!ExprCaptures.empty()) { + PreInit = new (Context) + DeclStmt(DeclGroupRef::Create(Context, ExprCaptures.begin(), + ExprCaptures.size()), + SourceLocation(), SourceLocation()); + } + Expr *PostUpdate = nullptr; + if (!ExprPostUpdates.empty()) { + for (auto *E : ExprPostUpdates) { + ExprResult PostUpdateRes = + PostUpdate + ? CreateBuiltinBinOp(SourceLocation(), BO_Comma, PostUpdate, E) + : E; + PostUpdate = PostUpdateRes.get(); + } + } + return OMPReductionClause::Create( Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars, ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, Privates, - LHSs, RHSs, ReductionOps); + LHSs, RHSs, ReductionOps, PreInit, PostUpdate); } OMPClause *Sema::ActOnOpenMPLinearClause( diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index e699889106..7eaeccf0fc 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -2063,6 +2063,8 @@ void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) { } void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) { + VisitOMPClauseWithPreInit(C); + VisitOMPClauseWithPostUpdate(C); C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); C->setColonLoc(Reader->ReadSourceLocation(Record, Idx)); NestedNameSpecifierLoc NNSL = diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 43a4f36d1d..0cebc1d977 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1911,6 +1911,8 @@ void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) { void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) { Record.push_back(C->varlist_size()); + VisitOMPClauseWithPreInit(C); + VisitOMPClauseWithPostUpdate(C); Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); Writer->Writer.AddSourceLocation(C->getColonLoc(), Record); Writer->Writer.AddNestedNameSpecifierLoc(C->getQualifierLoc(), Record); diff --git a/test/OpenMP/for_lastprivate_codegen.cpp b/test/OpenMP/for_lastprivate_codegen.cpp index 435a75c079..2ddd06aaef 100644 --- a/test/OpenMP/for_lastprivate_codegen.cpp +++ b/test/OpenMP/for_lastprivate_codegen.cpp @@ -148,7 +148,7 @@ int main() { // LAMBDA: define internal void [[SS_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}}) // LAMBDA: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* %{{.*}}, i32 0, i32 0 - // LAMBDA: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* %{{.*}}, i32 0, i32 1 + // LAMBDA-NOT: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* %{{.*}}, i32 0, i32 1 // LAMBDA: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* %{{.*}}, i32 0, i32 2 // LAMBDA: call void @__kmpc_for_static_init_4( // LAMBDA-NOT: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* @@ -326,7 +326,7 @@ int main() { // BLOCKS: define internal void [[SS_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}}) // BLOCKS: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* %{{.*}}, i32 0, i32 0 -// BLOCKS: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* %{{.*}}, i32 0, i32 1 +// BLOCKS-NOT: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* %{{.*}}, i32 0, i32 1 // BLOCKS: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* %{{.*}}, i32 0, i32 2 // BLOCKS: call void @__kmpc_for_static_init_4( // BLOCKS-NOT: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* diff --git a/test/OpenMP/parallel_reduction_codegen.cpp b/test/OpenMP/parallel_reduction_codegen.cpp index 05224d0a13..703750c233 100644 --- a/test/OpenMP/parallel_reduction_codegen.cpp +++ b/test/OpenMP/parallel_reduction_codegen.cpp @@ -20,6 +20,62 @@ struct S { ~S() {} }; +struct SS { + int a; + int b : 4; + int &c; + SS(int &d) : a(0), b(0), c(d) { +#pragma omp parallel reduction(+: a, b, c) +#ifdef LAMBDA + [&]() { + ++this->a, --b, (this)->c /= 1; +#pragma omp parallel reduction(&: a, b, c) + ++(this)->a, --b, this->c /= 1; + }(); +#elif defined(BLOCKS) + ^{ + ++a; + --this->b; + (this)->c /= 1; +#pragma omp parallel reduction(-: a, b, c) + ++(this)->a, --b, this->c /= 1; + }(); +#else + ++this->a, --b, c /= 1; +#endif + } +}; + +template +struct SST { + T a; + SST() : a(T()) { +#pragma omp parallel reduction(*: a) +#ifdef LAMBDA + [&]() { + [&]() { + ++this->a; +#pragma omp parallel reduction(&& :a) + ++(this)->a; + }(); + }(); +#elif defined(BLOCKS) + ^{ + ^{ + ++a; +#pragma omp parallel reduction(|: a) + ++(this)->a; + }(); + }(); +#else + ++(this)->a; +#endif + } +}; + +// CHECK: [[SS_TY:%.+]] = type { i{{[0-9]+}}, i8 +// LAMBDA: [[SS_TY:%.+]] = type { i{{[0-9]+}}, i8 +// BLOCKS: [[SS_TY:%.+]] = type { i{{[0-9]+}}, i8 // CHECK-DAG: [[S_FLOAT_TY:%.+]] = type { float } // CHECK-DAG: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} } // CHECK-DAG: [[REDUCTION_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 18, i32 0, i32 0, i8* @@ -29,6 +85,7 @@ template T tmain() { T t; S test; + SST sst; T t_var __attribute__((aligned(128))) = T(), t_var1 __attribute__((aligned(128))); T vec[] = {1, 2}; S s_arr[] = {1, 2}; @@ -41,16 +98,62 @@ T tmain() { return T(); } +int sivar; int main() { + SS ss(sivar); #ifdef LAMBDA // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212, // LAMBDA-LABEL: @main - // LAMBDA: call void [[OUTER_LAMBDA:@.+]]( + // LAMBDA: alloca [[SS_TY]], + // LAMBDA: alloca [[CAP_TY:%.+]], + // LAMBDA: call{{.*}} void [[OUTER_LAMBDA:@[^(]+]]([[CAP_TY]]* [&]() { // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]]( // LAMBDA: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i32* [[G]]) #pragma omp parallel reduction(+:g) { + // LAMBDA: define {{.+}} @{{.+}}([[SS_TY]]* + // LAMBDA: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 + // LAMBDA: store i{{[0-9]+}} 0, i{{[0-9]+}}* % + // LAMBDA: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 1 + // LAMBDA: store i8 + // LAMBDA: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 2 + // LAMBDA: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 + // LAMBDA-NOT: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 1 + // LAMBDA: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 2 + // LAMBDA: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*, i32*, i32*, i32*)* [[SS_MICROTASK:@.+]] to void + // LAMBDA: [[B_REF:%.+]] = getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* %{{.*}}, i32 0, i32 1 + // LAMBDA: store i8 %{{.+}}, i8* [[B_REF]], + // LAMBDA: ret + + // LAMBDA: define internal void [[SS_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}}, i32* {{.+}}, i32* {{.+}}, i32* {{.+}}) + // LAMBDA-NOT: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* % + // LAMBDA: call{{.*}} void + // LAMBDA: ret void + + // LAMBDA: define internal void @{{.+}}(i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* + // LAMBDA: [[A_PRIV:%.+]] = alloca i{{[0-9]+}}, + // LAMBDA: [[B_PRIV:%.+]] = alloca i{{[0-9]+}}, + // LAMBDA: [[C_PRIV:%.+]] = alloca i{{[0-9]+}}, + // LAMBDA: store i{{[0-9]+}} -1, i{{[0-9]+}}* [[A_PRIV]], + // LAMBDA: store i{{[0-9]+}}* [[A_PRIV]], i{{[0-9]+}}** [[REFA:%.+]], + // LAMBDA: store i{{[0-9]+}} -1, i{{[0-9]+}}* [[B_PRIV]], + // LAMBDA: store i{{[0-9]+}} -1, i{{[0-9]+}}* [[C_PRIV]], + // LAMBDA: store i{{[0-9]+}}* [[C_PRIV]], i{{[0-9]+}}** [[REFC:%.+]], + // LAMBDA: [[A_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REFA]], + // LAMBDA-NEXT: [[A_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[A_PRIV]], + // LAMBDA-NEXT: [[INC:%.+]] = add nsw i{{[0-9]+}} [[A_VAL]], 1 + // LAMBDA-NEXT: store i{{[0-9]+}} [[INC]], i{{[0-9]+}}* [[A_PRIV]], + // LAMBDA-NEXT: [[B_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[B_PRIV]], + // LAMBDA-NEXT: [[DEC:%.+]] = add nsw i{{[0-9]+}} [[B_VAL]], -1 + // LAMBDA-NEXT: store i{{[0-9]+}} [[DEC]], i{{[0-9]+}}* [[B_PRIV]], + // LAMBDA-NEXT: [[C_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REFC]], + // LAMBDA-NEXT: [[C_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[C_PRIV]], + // LAMBDA-NEXT: [[DIV:%.+]] = sdiv i{{[0-9]+}} [[C_VAL]], 1 + // LAMBDA-NEXT: store i{{[0-9]+}} [[DIV]], i{{[0-9]+}}* [[C_PRIV]], + // LAMBDA: call i32 @__kmpc_reduce_nowait( + // LAMBDA: ret void + // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* noalias %{{.+}}, i32* noalias %{{.+}}, i32* dereferenceable(4) %{{.+}}) // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, @@ -100,6 +203,7 @@ int main() { #elif defined(BLOCKS) // BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212, // BLOCKS-LABEL: @main + // BLOCKS: call // BLOCKS: call void {{%.+}}(i8 ^{ // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8* @@ -152,6 +256,47 @@ int main() { } }(); return 0; +// BLOCKS: define {{.+}} @{{.+}}([[SS_TY]]* +// BLOCKS: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 +// BLOCKS: store i{{[0-9]+}} 0, i{{[0-9]+}}* % +// BLOCKS: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 1 +// BLOCKS: store i8 +// BLOCKS: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 2 +// BLOCKS: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 +// BLOCKS-NOT: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 1 +// BLOCKS: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 2 +// BLOCKS: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*, i32*, i32*, i32*)* [[SS_MICROTASK:@.+]] to void +// BLOCKS: [[B_REF:%.+]] = getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* %{{.*}}, i32 0, i32 1 +// BLOCKS: store i8 %{{.+}}, i8* [[B_REF]], +// BLOCKS: ret + +// BLOCKS: define internal void [[SS_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}}, i32* {{.+}}, i32* {{.+}}, i32* {{.+}}) +// BLOCKS-NOT: getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* % +// BLOCKS: call{{.*}} void +// BLOCKS: ret void + +// BLOCKS: define internal void @{{.+}}(i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}}, i32* {{.+}}, i32* {{.+}}, i32* {{.+}}) +// BLOCKS: [[A_PRIV:%.+]] = alloca i{{[0-9]+}}, +// BLOCKS: [[B_PRIV:%.+]] = alloca i{{[0-9]+}}, +// BLOCKS: [[C_PRIV:%.+]] = alloca i{{[0-9]+}}, +// BLOCKS: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[A_PRIV]], +// BLOCKS: store i{{[0-9]+}}* [[A_PRIV]], i{{[0-9]+}}** [[REFA:%.+]], +// BLOCKS: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[B_PRIV]], +// BLOCKS: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[C_PRIV]], +// BLOCKS: store i{{[0-9]+}}* [[C_PRIV]], i{{[0-9]+}}** [[REFC:%.+]], +// BLOCKS: [[A_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REFA]], +// BLOCKS-NEXT: [[A_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[A_PRIV]], +// BLOCKS-NEXT: [[INC:%.+]] = add nsw i{{[0-9]+}} [[A_VAL]], 1 +// BLOCKS-NEXT: store i{{[0-9]+}} [[INC]], i{{[0-9]+}}* [[A_PRIV]], +// BLOCKS-NEXT: [[B_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[B_PRIV]], +// BLOCKS-NEXT: [[DEC:%.+]] = add nsw i{{[0-9]+}} [[B_VAL]], -1 +// BLOCKS-NEXT: store i{{[0-9]+}} [[DEC]], i{{[0-9]+}}* [[B_PRIV]], +// BLOCKS-NEXT: [[C_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REFC]], +// BLOCKS-NEXT: [[C_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[C_PRIV]], +// BLOCKS-NEXT: [[DIV:%.+]] = sdiv i{{[0-9]+}} [[C_VAL]], 1 +// BLOCKS-NEXT: store i{{[0-9]+}} [[DIV]], i{{[0-9]+}}* [[C_PRIV]], +// BLOCKS: call i32 @__kmpc_reduce_nowait( +// BLOCKS: ret void #else S test; float t_var = 0, t_var1; @@ -472,6 +617,43 @@ int main() { // CHECK: call {{.*}} [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* // CHECK: ret // +// CHECK: define {{.+}} @{{.+}}([[SS_TY]]* +// CHECK: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 +// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* % +// CHECK: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 1 +// CHECK: store i8 +// CHECK: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 2 +// CHECK: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 +// CHECK-NOT: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 1 +// CHECK: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 2 +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 4, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*, i{{[0-9]+}}*, i{{[0-9]+}}*, i{{[0-9]+}}*)* [[SS_MICROTASK:@.+]] to void +// CHECK: [[B_REF:%.+]] = getelementptr {{.*}}[[SS_TY]], [[SS_TY]]* %{{.*}}, i32 0, i32 1 +// CHECK: store i8 %{{.+}}, i8* [[B_REF]], +// CHECK: ret + +// CHECK: define internal void [[SS_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* +// CHECK: [[A_PRIV:%.+]] = alloca i{{[0-9]+}}, +// CHECK: [[B_PRIV:%.+]] = alloca i{{[0-9]+}}, +// CHECK: [[C_PRIV:%.+]] = alloca i{{[0-9]+}}, +// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[A_PRIV]], +// CHECK: store i{{[0-9]+}}* [[A_PRIV]], i{{[0-9]+}}** [[REFA:%.+]], +// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[B_PRIV]], +// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* [[C_PRIV]], +// CHECK: store i{{[0-9]+}}* [[C_PRIV]], i{{[0-9]+}}** [[REFC:%.+]], +// CHECK: [[A_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REFA]], +// CHECK-NEXT: [[A_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[A_PRIV]], +// CHECK-NEXT: [[INC:%.+]] = add nsw i{{[0-9]+}} [[A_VAL]], 1 +// CHECK-NEXT: store i{{[0-9]+}} [[INC]], i{{[0-9]+}}* [[A_PRIV]], +// CHECK-NEXT: [[B_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[B_PRIV]], +// CHECK-NEXT: [[DEC:%.+]] = add nsw i{{[0-9]+}} [[B_VAL]], -1 +// CHECK-NEXT: store i{{[0-9]+}} [[DEC]], i{{[0-9]+}}* [[B_PRIV]], +// CHECK-NEXT: [[C_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REFC]], +// CHECK-NEXT: [[C_VAL:%.+]] = load i{{[0-9]+}}, i{{[0-9]+}}* [[C_PRIV]], +// CHECK-NEXT: [[DIV:%.+]] = sdiv i{{[0-9]+}} [[C_VAL]], 1 +// CHECK-NEXT: store i{{[0-9]+}} [[DIV]], i{{[0-9]+}}* [[C_PRIV]], +// CHECK: call i32 @__kmpc_reduce_nowait( +// CHECK: ret void + // CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, // CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}}, align 128 // CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]], align 128 diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index b3f33ad8ff..db1849bba2 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -2178,6 +2178,8 @@ void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) { } void OMPClauseEnqueue::VisitOMPReductionClause(const OMPReductionClause *C) { VisitOMPClauseList(C); + VisitOMPClauseWithPreInit(C); + VisitOMPClauseWithPostUpdate(C); for (auto *E : C->privates()) { Visitor->AddStmt(E); } -- 2.40.0