From 90c228f0baee4e807f7355066f31c3438f1fcafd Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Mon, 8 Feb 2016 09:29:13 +0000 Subject: [PATCH] [OPENMP 4.5] Ccapture/codegen of private non-static data members. OpenMP 4.5 introduces privatization of non-static data members of current class in non-static member functions. To correctly handle such kind of privatization a new (pseudo)declaration VarDecl-based node is added. It allows to reuse an existing code for capturing variables in Lambdas/Block/Captured blocks of code for correct privatization and codegen. llvm-svn: 260077 --- clang/include/clang/AST/DeclOpenMP.h | 31 ++++- clang/include/clang/AST/RecursiveASTVisitor.h | 2 + clang/include/clang/Basic/DeclNodes.td | 1 + clang/include/clang/Sema/Sema.h | 4 +- clang/include/clang/Serialization/ASTBitCodes.h | 2 + clang/lib/AST/DeclBase.cpp | 1 + clang/lib/AST/DeclOpenMP.cpp | 21 +++- clang/lib/AST/DeclPrinter.cpp | 5 + clang/lib/AST/StmtPrinter.cpp | 14 ++- clang/lib/CodeGen/CGDecl.cpp | 1 + clang/lib/Sema/SemaExpr.cpp | 1 + clang/lib/Sema/SemaExprMember.cpp | 16 ++- clang/lib/Sema/SemaOpenMP.cpp | 94 +++++++++++--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 + clang/lib/Serialization/ASTCommon.cpp | 1 + clang/lib/Serialization/ASTReaderDecl.cpp | 8 ++ clang/lib/Serialization/ASTWriterDecl.cpp | 6 + clang/test/OpenMP/parallel_private_codegen.cpp | 160 ++++++++++++++++++++++++ clang/tools/libclang/CIndex.cpp | 1 + 19 files changed, 343 insertions(+), 31 deletions(-) diff --git a/clang/include/clang/AST/DeclOpenMP.h b/clang/include/clang/AST/DeclOpenMP.h index 524e78e..ed7cb35 100644 --- a/clang/include/clang/AST/DeclOpenMP.h +++ b/clang/include/clang/AST/DeclOpenMP.h @@ -87,6 +87,35 @@ public: static bool classofKind(Kind K) { return K == OMPThreadPrivate; } }; -} // end namespace clang +/// Pseudo declaration for capturing of non-static data members in non-static +/// member functions. +/// +/// Clang supports capturing of variables only, but OpenMP 4.5 allows to +/// privatize non-static members of current class in non-static member +/// functions. This pseudo-declaration allows properly handle this kind of +/// capture by wrapping captured expression into a variable-like declaration. +class OMPCapturedFieldDecl final : public VarDecl { + friend class ASTDeclReader; + void anchor() override; + + OMPCapturedFieldDecl(ASTContext &C, DeclContext *DC, IdentifierInfo *Id, + QualType Type) + : VarDecl(OMPCapturedField, C, DC, SourceLocation(), SourceLocation(), Id, + Type, nullptr, SC_None) { + setImplicit(); + } + +public: + static OMPCapturedFieldDecl *Create(ASTContext &C, DeclContext *DC, + IdentifierInfo *Id, QualType T); + + static OMPCapturedFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == OMPCapturedField; } +}; + +} // end namespace clang #endif diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 1a28bad..ea10df1 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1434,6 +1434,8 @@ DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, { } }) +DEF_TRAVERSE_DECL(OMPCapturedFieldDecl, { TRY_TO(TraverseVarHelper(D)); }) + // A helper method for TemplateDecl's children. template bool RecursiveASTVisitor::TraverseTemplateParameterListHelper( diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index 723ea54..490c5f2 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -51,6 +51,7 @@ def Named : Decl<1>; : DDecl; def ImplicitParam : DDecl; def ParmVar : DDecl; + def OMPCapturedField : DDecl; def NonTypeTemplateParm : DDecl; def Template : DDecl; def RedeclarableTemplate : DDecl; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 002abe8..7514373 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7789,7 +7789,9 @@ public: /// \brief Check if the specified variable is used in one of the private /// clauses (private, firstprivate, lastprivate, reduction etc.) in OpenMP /// constructs. - bool IsOpenMPCapturedDecl(ValueDecl *D); + VarDecl *IsOpenMPCapturedDecl(ValueDecl *D); + ExprResult getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, + ExprObjectKind OK); /// \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/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 5ee73f1..cc663d0 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1163,6 +1163,8 @@ namespace clang { DECL_EMPTY, /// \brief An ObjCTypeParamDecl record. DECL_OBJC_TYPE_PARAM, + /// \brief An OMPCapturedFieldDecl record. + DECL_OMP_CAPTUREDFIELD, }; /// \brief Record codes for each kind of statement or expression. diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 72587e3..b699bec 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -655,6 +655,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCCategoryImpl: case Import: case OMPThreadPrivate: + case OMPCapturedField: case Empty: // Never looked up by name. return 0; diff --git a/clang/lib/AST/DeclOpenMP.cpp b/clang/lib/AST/DeclOpenMP.cpp index 493e2cd..33677ba 100644 --- a/clang/lib/AST/DeclOpenMP.cpp +++ b/clang/lib/AST/DeclOpenMP.cpp @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// /// \file -/// \brief This file implements OMPThreadPrivateDecl class. +/// \brief This file implements OMPThreadPrivateDecl, OMPCapturedFieldDecl +/// classes. /// //===----------------------------------------------------------------------===// @@ -52,3 +53,21 @@ void OMPThreadPrivateDecl::setVars(ArrayRef VL) { std::uninitialized_copy(VL.begin(), VL.end(), getTrailingObjects()); } +//===----------------------------------------------------------------------===// +// OMPCapturedFieldDecl Implementation. +//===----------------------------------------------------------------------===// + +void OMPCapturedFieldDecl::anchor() {} + +OMPCapturedFieldDecl *OMPCapturedFieldDecl::Create(ASTContext &C, + DeclContext *DC, + IdentifierInfo *Id, + QualType T) { + return new (C, DC) OMPCapturedFieldDecl(C, DC, Id, T); +} + +OMPCapturedFieldDecl *OMPCapturedFieldDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + return new (C, ID) OMPCapturedFieldDecl(C, nullptr, nullptr, QualType()); +} + diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 19c7da3..1a0e148 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -92,6 +92,7 @@ namespace { void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPCapturedFieldDecl(OMPCapturedFieldDecl *D); void PrintTemplateParameters(const TemplateParameterList *Params, const TemplateArgumentList *Args = nullptr); @@ -1366,3 +1367,7 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { } } +void DeclPrinter::VisitOMPCapturedFieldDecl(OMPCapturedFieldDecl *D) { + D->getInit()->printPretty(Out, nullptr, Policy, Indentation); +} + diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index d9c3457..830eeb9 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -763,15 +764,16 @@ template void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) { for (typename T::varlist_iterator I = Node->varlist_begin(), E = Node->varlist_end(); - I != E; ++I) { + I != E; ++I) { assert(*I && "Expected non-null Stmt"); + OS << (I == Node->varlist_begin() ? StartSym : ','); if (DeclRefExpr *DRE = dyn_cast(*I)) { - OS << (I == Node->varlist_begin() ? StartSym : ','); - cast(DRE->getDecl())->printQualifiedName(OS); - } else { - OS << (I == Node->varlist_begin() ? StartSym : ','); + if (auto *CFD = dyn_cast(DRE->getDecl())) + CFD->getInit()->IgnoreImpCasts()->printPretty(OS, nullptr, Policy, 0); + else + DRE->getDecl()->printQualifiedName(OS); + } else (*I)->printPretty(OS, nullptr, Policy, 0); - } } } diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index e8a4d55..e18e86d 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -92,6 +92,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Label: // __label__ x; case Decl::Import: case Decl::OMPThreadPrivate: + case Decl::OMPCapturedField: case Decl::Empty: // None of these decls require codegen support. return; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 20a0e3f..0c17aa1 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2874,6 +2874,7 @@ ExprResult Sema::BuildDeclarationNameExpr( case Decl::Var: case Decl::VarTemplateSpecialization: case Decl::VarTemplatePartialSpecialization: + case Decl::OMPCapturedField: // In C, "extern void blah;" is valid and is an r-value. if (!getLangOpts().CPlusPlus && !type.hasQualifiers() && diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index f62b5a5..4155874 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1735,9 +1735,19 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, FoundDecl, Field); if (Base.isInvalid()) return ExprError(); - return BuildMemberExpr(S, S.Context, Base.get(), IsArrow, OpLoc, SS, - /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl, - MemberNameInfo, MemberType, VK, OK); + MemberExpr *ME = + BuildMemberExpr(S, S.Context, Base.get(), IsArrow, OpLoc, SS, + /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl, + MemberNameInfo, MemberType, VK, OK); + + // Build a reference to a private copy for non-static data members in + // non-static member functions, privatized by OpenMP constructs. + if (S.getLangOpts().OpenMP && IsArrow && + isa(Base.get()->IgnoreParenImpCasts())) { + if (auto *PrivateCopy = S.IsOpenMPCapturedDecl(Field)) + return S.getOpenMPCapturedExpr(PrivateCopy, VK, OK); + } + return ME; } /// Builds an implicit member access expression. The current context diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 5b38f43..d4c1f98 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -71,10 +71,11 @@ public: OpenMPDirectiveKind DKind; OpenMPClauseKind CKind; Expr *RefExpr; + DeclRefExpr *PrivateCopy; SourceLocation ImplicitDSALoc; DSAVarData() : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(nullptr), - ImplicitDSALoc() {} + PrivateCopy(nullptr), ImplicitDSALoc() {} }; private: @@ -83,11 +84,12 @@ private: struct DSAInfo { OpenMPClauseKind Attributes; Expr *RefExpr; + DeclRefExpr *PrivateCopy; }; - typedef llvm::SmallDenseMap DeclSAMapTy; - typedef llvm::SmallDenseMap AlignedMapTy; + typedef llvm::DenseMap DeclSAMapTy; + typedef llvm::DenseMap AlignedMapTy; typedef llvm::DenseMap LoopControlVariablesMapTy; - typedef llvm::SmallDenseMap MappedDeclsTy; + typedef llvm::DenseMap MappedDeclsTy; typedef llvm::StringMap> CriticalsWithHintsTy; @@ -195,7 +197,8 @@ public: ValueDecl *getParentLoopControlVariable(unsigned I); /// \brief Adds explicit data sharing attribute to the specified declaration. - void addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A); + void addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, + DeclRefExpr *PrivateCopy = nullptr); /// \brief Returns data sharing attributes from top of the stack for the /// specified declaration. @@ -434,6 +437,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // attributes. if (Iter->SharingMap.count(D)) { DVar.RefExpr = Iter->SharingMap[D].RefExpr; + DVar.PrivateCopy = Iter->SharingMap[D].PrivateCopy; DVar.CKind = Iter->SharingMap[D].Attributes; DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; return DVar; @@ -547,15 +551,20 @@ ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) { return nullptr; } -void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A) { +void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, + DeclRefExpr *PrivateCopy) { D = getCanonicalDecl(D); if (A == OMPC_threadprivate) { Stack[0].SharingMap[D].Attributes = A; Stack[0].SharingMap[D].RefExpr = E; + Stack[0].SharingMap[D].PrivateCopy = nullptr; } else { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); Stack.back().SharingMap[D].Attributes = A; Stack.back().SharingMap[D].RefExpr = E; + Stack.back().SharingMap[D].PrivateCopy = PrivateCopy; + if (PrivateCopy) + addDSA(PrivateCopy->getDecl(), PrivateCopy, A); } } @@ -682,6 +691,7 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { auto I = std::prev(StartI); if (I->SharingMap.count(D)) { DVar.RefExpr = I->SharingMap[D].RefExpr; + DVar.PrivateCopy = I->SharingMap[D].PrivateCopy; DVar.CKind = I->SharingMap[D].Attributes; DVar.ImplicitDSALoc = I->DefaultAttrLoc; } @@ -886,7 +896,7 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, return IsByRef; } -bool Sema::IsOpenMPCapturedDecl(ValueDecl *D) { +VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); D = getCanonicalDecl(D); @@ -900,18 +910,16 @@ bool Sema::IsOpenMPCapturedDecl(ValueDecl *D) { auto *VD = dyn_cast(D); if (VD && !VD->hasLocalStorage()) { if (DSAStack->getCurrentDirective() == OMPD_target && - !DSAStack->isClauseParsingMode()) { - return true; - } + !DSAStack->isClauseParsingMode()) + return VD; if (DSAStack->getCurScope() && DSAStack->hasDirective( [](OpenMPDirectiveKind K, const DeclarationNameInfo &DNI, SourceLocation Loc) -> bool { return isOpenMPTargetExecutionDirective(K); }, - false)) { - return true; - } + false)) + return VD; } if (DSAStack->getCurrentDirective() != OMPD_unknown && @@ -921,15 +929,16 @@ bool Sema::IsOpenMPCapturedDecl(ValueDecl *D) { (VD && VD->hasLocalStorage() && isParallelOrTaskRegion(DSAStack->getCurrentDirective())) || (VD && DSAStack->isForceVarCapturing())) - return true; + return VD; auto DVarPrivate = DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode()); if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) - return true; + return VD ? VD : cast(DVarPrivate.PrivateCopy->getDecl()); DVarPrivate = DSAStack->hasDSA(D, isOpenMPPrivate, MatchesAlways(), DSAStack->isClauseParsingMode()); - return DVarPrivate.CKind != OMPC_unknown; + if (DVarPrivate.CKind != OMPC_unknown) + return VD ? VD : cast(DVarPrivate.PrivateCopy->getDecl()); } - return false; + return nullptr; } bool Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level) { @@ -6958,6 +6967,50 @@ OMPClause *Sema::ActOnOpenMPVarListClause( return Res; } +static DeclRefExpr *buildCapture(Sema &S, IdentifierInfo *Id, + Expr *CaptureExpr) { + ASTContext &C = S.getASTContext(); + Expr *Init = CaptureExpr->IgnoreImpCasts(); + QualType Ty = Init->getType(); + if (CaptureExpr->getObjectKind() == OK_Ordinary) { + if (S.getLangOpts().CPlusPlus) + Ty = C.getLValueReferenceType(Ty); + else { + Ty = C.getPointerType(Ty); + ExprResult Res = + S.CreateBuiltinUnaryOp(CaptureExpr->getExprLoc(), UO_AddrOf, Init); + if (!Res.isUsable()) + return nullptr; + Init = Res.get(); + } + } + auto *CFD = OMPCapturedFieldDecl::Create(C, S.CurContext, Id, Ty); + S.CurContext->addHiddenDecl(CFD); + S.AddInitializerToDecl(CFD, Init, /*DirectInit=*/false, + /*TypeMayContainAuto=*/true); + return buildDeclRefExpr(S, CFD, Ty.getNonReferenceType(), SourceLocation()); +} + +ExprResult Sema::getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, + ExprObjectKind OK) { + SourceLocation Loc = Capture->getInit()->getExprLoc(); + ExprResult Res = BuildDeclRefExpr( + Capture, Capture->getType().getNonReferenceType(), VK_LValue, Loc); + if (!Res.isUsable()) + return ExprError(); + if (OK == OK_Ordinary && !getLangOpts().CPlusPlus) { + Res = CreateBuiltinUnaryOp(Loc, UO_Deref, Res.get()); + if (!Res.isUsable()) + return ExprError(); + } + if (VK != VK_LValue && Res.get()->isGLValue()) { + Res = DefaultLvalueConversion(Res.get()); + if (!Res.isUsable()) + return ExprError(); + } + return Res; +} + OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -7050,8 +7103,11 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, auto VDPrivateRefExpr = buildDeclRefExpr( *this, VDPrivate, RefExpr->getType().getUnqualifiedType(), ELoc); - DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private); - Vars.push_back(RefExpr->IgnoreParens()); + DeclRefExpr *Ref = nullptr; + if (!VD) + Ref = buildCapture(*this, D->getIdentifier(), RefExpr); + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref); + Vars.push_back(VD ? RefExpr->IgnoreParens() : Ref); PrivateCopies.push_back(VDPrivateRefExpr); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 625760c..0f011ab 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2483,6 +2483,11 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( return TD; } +Decl *TemplateDeclInstantiator::VisitOMPCapturedFieldDecl( + OMPCapturedFieldDecl * /*D*/) { + llvm_unreachable("Should not be met in templates"); +} + Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) { return VisitFunctionDecl(D, nullptr); } diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index 2b78d74..68621f3 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -329,6 +329,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::ClassScopeFunctionSpecialization: case Decl::Import: case Decl::OMPThreadPrivate: + case Decl::OMPCapturedField: case Decl::BuiltinTemplate: return false; diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index b249da9..074de1a 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -350,6 +350,7 @@ namespace clang { void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPCapturedFieldDecl(OMPCapturedFieldDecl *D); /// We've merged the definition \p MergedDef into the existing definition /// \p Def. Ensure that \p Def is made visible whenever \p MergedDef is made @@ -2360,6 +2361,10 @@ void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { D->setVars(Vars); } +void ASTDeclReader::VisitOMPCapturedFieldDecl(OMPCapturedFieldDecl *D) { + VisitVarDecl(D); +} + //===----------------------------------------------------------------------===// // Attribute Reading //===----------------------------------------------------------------------===// @@ -3323,6 +3328,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_OMP_THREADPRIVATE: D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, Record[Idx++]); break; + case DECL_OMP_CAPTUREDFIELD: + D = OMPCapturedFieldDecl::CreateDeserialized(Context, ID); + break; case DECL_EMPTY: D = EmptyDecl::CreateDeserialized(Context, ID); break; diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 54bba28..4620f56 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -131,6 +131,7 @@ namespace clang { void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPCapturedFieldDecl(OMPCapturedFieldDecl *D); /// Add an Objective-C type parameter list to the given record. void AddObjCTypeParamList(ObjCTypeParamList *typeParams) { @@ -1628,6 +1629,11 @@ void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { Code = serialization::DECL_OMP_THREADPRIVATE; } +void ASTDeclWriter::VisitOMPCapturedFieldDecl(OMPCapturedFieldDecl *D) { + VisitVarDecl(D); + Code = serialization::DECL_OMP_CAPTUREDFIELD; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// diff --git a/clang/test/OpenMP/parallel_private_codegen.cpp b/clang/test/OpenMP/parallel_private_codegen.cpp index 1d195be..948d02a 100644 --- a/clang/test/OpenMP/parallel_private_codegen.cpp +++ b/clang/test/OpenMP/parallel_private_codegen.cpp @@ -18,11 +18,69 @@ struct S { volatile int g __attribute__((aligned(128))) = 1212; +struct SS { + int a; + int b : 4; + int &c; + SS(int &d) : a(0), b(0), c(d) { +#pragma omp parallel private(a, b, c) +#ifdef LAMBDA + [&]() { + ++this->a, --b, (this)->c /= 1; +#pragma omp parallel private(a, b, c) + ++(this)->a, --b, this->c /= 1; + }(); +#elif defined(BLOCKS) + ^{ + ++a; + --this->b; + (this)->c /= 1; +#pragma omp parallel private(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 private(a) +#ifdef LAMBDA + [&]() { + [&]() { + ++this->a; +#pragma omp parallel private(a) + ++(this)->a; + }(); + }(); +#elif defined(BLOCKS) + ^{ + ^{ + ++a; +#pragma omp parallel private(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: [[S_FLOAT_TY:%.+]] = type { float } // CHECK: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} } +// CHECK: [[SST_TY:%.+]] = type { i{{[0-9]+}} } template T tmain() { S test; + SST sst; T t_var __attribute__((aligned(128))) = T(); T vec[] __attribute__((aligned(128))) = {1, 2}; S s_arr[] __attribute__((aligned(128))) = {1, 2}; @@ -37,9 +95,11 @@ T tmain() { int main() { static int sivar; + SS ss(sivar); #ifdef LAMBDA // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212, // LAMBDA-LABEL: @main + // LAMBDA: call // LAMBDA: call{{.*}} void [[OUTER_LAMBDA:@.+]]( [&]() { // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]]( @@ -47,6 +107,36 @@ int main() { // LAMBDA: call{{.*}} void {{.+}} @__kmpc_fork_call({{.+}}, i32 0, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}) #pragma omp parallel private(g, sivar) { + // LAMBDA: define {{.+}} @{{.+}}([[SS_TY]]* % + // LAMBDA: store i{{[0-9]+}} 0, i{{[0-9]+}}* % + // LAMBDA: store i8 + // LAMBDA: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*)* [[SS_MICROTASK:@.+]] to void + // LAMBDA: ret + + // LAMBDA: define internal void [[SS_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}}) + // 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]+}}* [[A_PRIV]], i{{[0-9]+}}** [[REFA:%.+]], + // LAMBDA: store i{{[0-9]+}}* [[C_PRIV]], i{{[0-9]+}}** [[REFC:%.+]], + // LAMBDA-NEXT: [[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-NEXT: ret void + // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* noalias %{{.+}}, i32* noalias %{{.+}}) // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, // LAMBDA: [[SIVAR_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, @@ -80,6 +170,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* @@ -116,6 +207,35 @@ int main() { } }(); return 0; +// BLOCKS: define {{.+}} @{{.+}}([[SS_TY]]* % +// BLOCKS: store i{{[0-9]+}} 0, i{{[0-9]+}}* % +// BLOCKS: store i8 +// BLOCKS: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*)* [[SS_MICROTASK:@.+]] to void +// BLOCKS: ret + +// BLOCKS: define internal void [[SS_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}}) +// 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]]* %{{.+}}) +// 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]+}}* [[A_PRIV]], i{{[0-9]+}}** [[REFA:%.+]], +// BLOCKS: store i{{[0-9]+}}* [[C_PRIV]], i{{[0-9]+}}** [[REFC:%.+]], +// BLOCKS-NEXT: [[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-NEXT: ret void #else S test; int t_var = 0; @@ -166,6 +286,31 @@ int main() { // CHECK: call void [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* // CHECK: ret // +// CHECK: define {{.+}} @{{.+}}([[SS_TY]]* % +// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* % +// CHECK: store i8 +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*)* [[SS_MICROTASK:@.+]] to void +// 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]+}}* [[A_PRIV]], i{{[0-9]+}}** [[REFA:%.+]], +// CHECK: store i{{[0-9]+}}* [[C_PRIV]], i{{[0-9]+}}** [[REFC:%.+]], +// CHECK-NEXT: [[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-NEXT: 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: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}], align 128 @@ -184,5 +329,20 @@ int main() { // CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]]) // CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]* // CHECK: ret void + +// CHECK: define {{.+}} @{{.+}}([[SST_TY]]* % +// CHECK: store i{{[0-9]+}} 0, i{{[0-9]+}}* % +// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SST_TY]]*)* [[SST_MICROTASK:@.+]] to void +// CHECK: ret + +// CHECK: define internal void [[SST_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SST_TY]]* %{{.+}}) +// CHECK: [[A_PRIV:%.+]] = alloca i{{[0-9]+}}, +// CHECK: store i{{[0-9]+}}* [[A_PRIV]], i{{[0-9]+}}** [[REF:%.+]], +// CHECK-NEXT: [[A_PRIV:%.+]] = load i{{[0-9]+}}*, i{{[0-9]+}}** [[REF]], +// 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: ret void + #endif diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index e121933..1dbe056 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -5669,6 +5669,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::StaticAssert: case Decl::Block: case Decl::Captured: + case Decl::OMPCapturedField: case Decl::Label: // FIXME: Is this right?? case Decl::ClassScopeFunctionSpecialization: case Decl::Import: -- 2.7.4