From: Alexey Bataev Date: Tue, 21 Oct 2014 03:16:40 +0000 (+0000) Subject: [OPENMP] Codegen for 'private' clause in 'parallel' directive. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5b6e44a95460d91979a4436c81c7cd8c3264c95b;p=clang [OPENMP] Codegen for 'private' clause in 'parallel' directive. This patch generates some helper variables which used as a private copies of the corresponding original variables inside an OpenMP 'parallel' directive. These generated variables are initialized by default (with the default constructor, if any). In outlined function references to original variables are replaced by the references to these private helper variables. At the end of the initialization of the private variables and implicit barier is set by calling __kmpc_barrier(...) runtime function to be sure that all threads were initialized using original values of the variables. Differential Revision: http://reviews.llvm.org/D4752 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@220262 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DataRecursiveASTVisitor.h b/include/clang/AST/DataRecursiveASTVisitor.h index 6d9ac94a43..54c22fbda3 100644 --- a/include/clang/AST/DataRecursiveASTVisitor.h +++ b/include/clang/AST/DataRecursiveASTVisitor.h @@ -2478,6 +2478,9 @@ bool RecursiveASTVisitor::VisitOMPClauseList(T *Node) { template bool RecursiveASTVisitor::VisitOMPPrivateClause(OMPPrivateClause *C) { TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->private_copies()) { + TRY_TO(TraverseStmt(E)); + } return true; } diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h index 7d0c7d2ab0..30ce1aaeec 100644 --- a/include/clang/AST/OpenMPClause.h +++ b/include/clang/AST/OpenMPClause.h @@ -138,7 +138,7 @@ public: return llvm::makeArrayRef( reinterpret_cast( reinterpret_cast(this) + - llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf())), + llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf())), NumVars); } }; @@ -926,6 +926,7 @@ public: /// with the variables 'a' and 'b'. /// class OMPPrivateClause : public OMPVarListClause { + friend class OMPClauseReader; /// \brief Build clause with number of variables \a N. /// /// \param StartLoc Starting location of the clause. @@ -947,6 +948,20 @@ class OMPPrivateClause : public OMPVarListClause { SourceLocation(), SourceLocation(), N) {} + /// \brief Sets the list of references to private copies with initializers for + /// new private variables. + /// \param InitVL List of references. + void setPrivateCopies(ArrayRef VL); + + /// \brief Gets the list of references to private copies with initializers for + /// new private variables. + MutableArrayRef getPrivateCopies() { + return MutableArrayRef(varlist_end(), varlist_size()); + } + ArrayRef getPrivateCopies() const { + return llvm::makeArrayRef(varlist_end(), varlist_size()); + } + public: /// \brief Creates clause with a list of variables \a VL. /// @@ -955,10 +970,12 @@ public: /// \param LParenLoc Location of '('. /// \param EndLoc Ending location of the clause. /// \param VL List of references to the variables. + /// \param PrivateVL List of references to private copies with initializers. /// static OMPPrivateClause *Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, ArrayRef VL); + SourceLocation EndLoc, ArrayRef VL, + ArrayRef PrivateVL); /// \brief Creates an empty clause with the place for \a N variables. /// /// \param C AST context. @@ -966,6 +983,21 @@ public: /// static OMPPrivateClause *CreateEmpty(const ASTContext &C, unsigned N); + typedef MutableArrayRef::iterator private_copies_iterator; + typedef ArrayRef::iterator private_copies_const_iterator; + typedef llvm::iterator_range private_copies_range; + typedef llvm::iterator_range + private_copies_const_range; + + private_copies_range private_copies() { + return private_copies_range(getPrivateCopies().begin(), + getPrivateCopies().end()); + } + private_copies_const_range private_copies() const { + return private_copies_const_range(getPrivateCopies().begin(), + getPrivateCopies().end()); + } + StmtRange children() { return StmtRange(reinterpret_cast(varlist_begin()), reinterpret_cast(varlist_end())); diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 2f26801f94..bda4916201 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -2500,6 +2500,9 @@ bool RecursiveASTVisitor::VisitOMPClauseList(T *Node) { template bool RecursiveASTVisitor::VisitOMPPrivateClause(OMPPrivateClause *C) { TRY_TO(VisitOMPClauseList(C)); + for (auto *E : C->private_copies()) { + TRY_TO(TraverseStmt(E)); + } return true; } diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index ae381361c2..96865180a9 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -1176,17 +1176,24 @@ StmtRange OMPClause::children() { llvm_unreachable("unknown OMPClause"); } -OMPPrivateClause *OMPPrivateClause::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef VL) { +void OMPPrivateClause::setPrivateCopies(ArrayRef VL) { + assert(VL.size() == varlist_size() && + "Number of private copies is not the same as the preallocated buffer"); + std::copy(VL.begin(), VL.end(), varlist_end()); +} + +OMPPrivateClause * +OMPPrivateClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc, + ArrayRef VL, ArrayRef PrivateVL) { + // Allocate space for private variables and initializer expressions. void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause), llvm::alignOf()) + - sizeof(Expr *) * VL.size()); - OMPPrivateClause *Clause = new (Mem) OMPPrivateClause(StartLoc, LParenLoc, - EndLoc, VL.size()); + 2 * sizeof(Expr *) * VL.size()); + OMPPrivateClause *Clause = + new (Mem) OMPPrivateClause(StartLoc, LParenLoc, EndLoc, VL.size()); Clause->setVarRefs(VL); + Clause->setPrivateCopies(PrivateVL); return Clause; } @@ -1194,7 +1201,7 @@ OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C, unsigned N) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause), llvm::alignOf()) + - sizeof(Expr *) * N); + 2 * sizeof(Expr *) * N); return new (Mem) OMPPrivateClause(N); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index f06c36e0b6..87e30bb3e3 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -322,12 +322,16 @@ void OMPClauseProfiler::VisitOMPSeqCstClause(const OMPSeqCstClause *) {} template void OMPClauseProfiler::VisitOMPClauseList(T *Node) { - for (auto *I : Node->varlists()) - Profiler->VisitStmt(I); + for (auto *E : Node->varlists()) { + Profiler->VisitStmt(E); + } } void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) { VisitOMPClauseList(C); + for (auto *E : C->private_copies()) { + Profiler->VisitStmt(E); + } } void OMPClauseProfiler::VisitOMPFirstprivateClause(const OMPFirstprivateClause *C) { diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index 1a50c94bc7..06dd680bc7 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -71,6 +71,7 @@ LValue CGOpenMPRegionInfo::getThreadIDVariableLValue(CodeGenFunction &CGF) { void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, Stmt *S) { CodeGenFunction::OMPPrivateScope PrivateScope(CGF); + CGF.EmitOMPPrivateClause(Directive, PrivateScope); CGF.EmitOMPFirstprivateClause(Directive, PrivateScope); if (PrivateScope.Privatize()) { // Emit implicit barrier to synchronize threads and avoid data races. @@ -200,7 +201,10 @@ llvm::Value *CGOpenMPRuntime::GetOpenMPThreadID(CodeGenFunction &CGF, OpenMPLocThreadIDMapTy::iterator I = OpenMPLocThreadIDMap.find(CGF.CurFn); if (I != OpenMPLocThreadIDMap.end()) { ThreadID = I->second.ThreadID; - } else if (auto OMPRegionInfo = + if (ThreadID != nullptr) + return ThreadID; + } + if (auto OMPRegionInfo = dyn_cast_or_null(CGF.CapturedStmtInfo)) { // Check if this an outlined function with thread id passed as argument. auto ThreadIDVar = OMPRegionInfo->getThreadIDVariable(); @@ -233,7 +237,8 @@ llvm::Value *CGOpenMPRuntime::GetOpenMPThreadID(CodeGenFunction &CGF, void CGOpenMPRuntime::FunctionFinished(CodeGenFunction &CGF) { assert(CGF.CurFn && "No function in current CodeGenFunction."); - OpenMPLocThreadIDMap.erase(CGF.CurFn); + if (OpenMPLocThreadIDMap.count(CGF.CurFn)) + OpenMPLocThreadIDMap.erase(CGF.CurFn); } llvm::Type *CGOpenMPRuntime::getIdentTyPointerTy() { diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index 2b0fb043be..0e55993f92 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -183,6 +183,33 @@ void CodeGenFunction::EmitOMPFirstprivateClause( } } +void CodeGenFunction::EmitOMPPrivateClause( + const OMPExecutableDirective &D, + CodeGenFunction::OMPPrivateScope &PrivateScope) { + auto PrivateFilter = [](const OMPClause *C) -> bool { + return C->getClauseKind() == OMPC_private; + }; + for (OMPExecutableDirective::filtered_clause_iterator + I(D.clauses(), PrivateFilter); I; ++I) { + auto *C = cast(*I); + auto IRef = C->varlist_begin(); + for (auto IInit : C->private_copies()) { + auto *OrigVD = cast(cast(*IRef)->getDecl()); + auto VD = cast(cast(IInit)->getDecl()); + bool IsRegistered = + PrivateScope.addPrivate(OrigVD, [&]() -> llvm::Value * { + // Emit private VarDecl with copy init. + EmitDecl(*VD); + return GetAddrOfLocalVar(VD); + }); + assert(IsRegistered && "counter already registered as private"); + // Silence the warning about unused variable. + (void)IsRegistered; + ++IRef; + } + } +} + /// \brief Emits code for OpenMP parallel directive in the parallel region. static void EmitOMPParallelCall(CodeGenFunction &CGF, const OMPParallelDirective &S, diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 49810a8700..a31cd1bf7a 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -113,6 +113,7 @@ class CodeGenFunction : public CodeGenTypeCache { void operator=(const CodeGenFunction &) LLVM_DELETED_FUNCTION; friend class CGCXXABI; + friend class CGOpenMPRegionInfo; public: /// A jump destination is an abstract label, branching to which may /// require a jump out through normal cleanups. @@ -2012,6 +2013,8 @@ public: const VarDecl *VDInit); void EmitOMPFirstprivateClause(const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope); + void EmitOMPPrivateClause(const OMPExecutableDirective &D, + OMPPrivateScope &PrivateScope); void EmitOMPParallelDirective(const OMPParallelDirective &S); void EmitOMPSimdDirective(const OMPSimdDirective &S); diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 133bffab4f..b7c773dd16 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -3912,11 +3912,13 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector Vars; + SmallVector PrivateCopies; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP private clause."); if (isa(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + PrivateCopies.push_back(nullptr); continue; } @@ -3938,6 +3940,7 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); + PrivateCopies.push_back(nullptr); continue; } @@ -3963,54 +3966,8 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, // A variable of class type (or array thereof) that appears in a private // clause requires an accessible, unambiguous default constructor for the // class type. - while (Type.getNonReferenceType()->isArrayType()) { - Type = cast(Type.getNonReferenceType().getTypePtr()) - ->getElementType(); - } - CXXRecordDecl *RD = getLangOpts().CPlusPlus - ? Type.getNonReferenceType()->getAsCXXRecordDecl() - : nullptr; - // FIXME This code must be replaced by actual constructing/destructing of - // the private variable. - if (RD) { - CXXConstructorDecl *CD = LookupDefaultConstructor(RD); - PartialDiagnostic PD = - PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); - if (!CD || - CheckConstructorAccess(ELoc, CD, - InitializedEntity::InitializeTemporary(Type), - CD->getAccess(), PD) == AR_inaccessible || - CD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_private) << 0; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, CD); - DiagnoseUseOfDecl(CD, ELoc); - - CXXDestructorDecl *DD = RD->getDestructor(); - if (DD) { - if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || - DD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_private) << 4; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, DD); - DiagnoseUseOfDecl(DD, ELoc); - } + while (Type->isArrayType()) { + Type = cast(Type.getTypePtr())->getElementType(); } // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -4028,14 +3985,35 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, continue; } + // Generate helper private variable and initialize it with the default + // value. The address of the original variable is replaced by the address of + // the new private variable in CodeGen. This new variable is not added to + // IdResolver, so the code in the OpenMP region uses original variable for + // proper diagnostics. + auto VDPrivate = + VarDecl::Create(Context, CurContext, DE->getLocStart(), + DE->getExprLoc(), VD->getIdentifier(), VD->getType(), + VD->getTypeSourceInfo(), /*S*/ SC_Auto); + ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto*/ false); + if (VDPrivate->isInvalidDecl()) + continue; + CurContext->addDecl(VDPrivate); + auto VDPrivateRefExpr = DeclRefExpr::Create( + Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), + /*TemplateKWLoc*/ SourceLocation(), VDPrivate, + /*isEnclosingLocal*/ false, /*NameLoc*/ SourceLocation(), DE->getType(), + /*VK*/ VK_LValue); + DSAStack->addDSA(VD, DE, OMPC_private); Vars.push_back(DE); + PrivateCopies.push_back(VDPrivateRefExpr); } if (Vars.empty()) return nullptr; - return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); + return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, + PrivateCopies); } namespace { diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 7a20f7fed0..0cb65263ec 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1845,6 +1845,10 @@ void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) { for (unsigned i = 0; i != NumVars; ++i) Vars.push_back(Reader->Reader.ReadSubExpr()); C->setVarRefs(Vars); + Vars.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader->Reader.ReadSubExpr()); + C->setPrivateCopies(Vars); } void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index ff42c8301d..6891f56e2d 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1755,8 +1755,12 @@ void OMPClauseWriter::VisitOMPSeqCstClause(OMPSeqCstClause *) {} void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { Record.push_back(C->varlist_size()); Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlists()) { + Writer->Writer.AddStmt(VE); + } + for (auto *VE : C->private_copies()) { Writer->Writer.AddStmt(VE); + } } void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { diff --git a/test/OpenMP/for_private_messages.cpp b/test/OpenMP/for_private_messages.cpp index f7a497930d..45c8683cfa 100644 --- a/test/OpenMP/for_private_messages.cpp +++ b/test/OpenMP/for_private_messages.cpp @@ -24,16 +24,16 @@ public: S3() : a(0) {} }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -109,8 +109,8 @@ int foomain(I argc, C **argv) { } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp for private // expected-error {{expected '(' after 'private'}} @@ -143,7 +143,7 @@ int main(int argc, char **argv) { #pragma omp for private(argv[1]) // expected-error {{expected variable name}} for (int k = 0; k < argc; ++k) ++k; -#pragma omp for private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp for private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} for (int k = 0; k < argc; ++k) ++k; #pragma omp for private(h) // expected-error {{threadprivate or thread local variable cannot be private}} diff --git a/test/OpenMP/for_simd_private_messages.cpp b/test/OpenMP/for_simd_private_messages.cpp index 237b5a9fa0..016a5ec6b5 100644 --- a/test/OpenMP/for_simd_private_messages.cpp +++ b/test/OpenMP/for_simd_private_messages.cpp @@ -24,16 +24,16 @@ public: S3() : a(0) {} }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -109,8 +109,8 @@ int foomain(I argc, C **argv) { } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp for simd private // expected-error {{expected '(' after 'private'}} @@ -143,7 +143,7 @@ int main(int argc, char **argv) { #pragma omp for simd private(argv[1]) // expected-error {{expected variable name}} for (int k = 0; k < argc; ++k) ++k; -#pragma omp for simd private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp for simd private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} for (int k = 0; k < argc; ++k) ++k; #pragma omp for simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}} diff --git a/test/OpenMP/parallel_for_private_messages.cpp b/test/OpenMP/parallel_for_private_messages.cpp index 7366fe8c47..31b84588de 100644 --- a/test/OpenMP/parallel_for_private_messages.cpp +++ b/test/OpenMP/parallel_for_private_messages.cpp @@ -24,16 +24,16 @@ public: S3() : a(0) {} }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -109,8 +109,8 @@ int foomain(I argc, C **argv) { } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel for private // expected-error {{expected '(' after 'private'}} @@ -143,7 +143,7 @@ int main(int argc, char **argv) { #pragma omp parallel for private(argv[1]) // expected-error {{expected variable name}} for (int k = 0; k < argc; ++k) ++k; -#pragma omp parallel for private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp parallel for private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} for (int k = 0; k < argc; ++k) ++k; #pragma omp parallel for private(h) // expected-error {{threadprivate or thread local variable cannot be private}} diff --git a/test/OpenMP/parallel_for_simd_private_messages.cpp b/test/OpenMP/parallel_for_simd_private_messages.cpp index 3208ccc89d..67d8813186 100644 --- a/test/OpenMP/parallel_for_simd_private_messages.cpp +++ b/test/OpenMP/parallel_for_simd_private_messages.cpp @@ -24,16 +24,16 @@ public: S3() : a(0) {} }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -109,8 +109,8 @@ int foomain(I argc, C **argv) { } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel for simd private // expected-error {{expected '(' after 'private'}} @@ -143,7 +143,7 @@ int main(int argc, char **argv) { #pragma omp parallel for simd private(argv[1]) // expected-error {{expected variable name}} for (int k = 0; k < argc; ++k) ++k; -#pragma omp parallel for simd private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp parallel for simd private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} for (int k = 0; k < argc; ++k) ++k; #pragma omp parallel for simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}} diff --git a/test/OpenMP/parallel_private_codegen.cpp b/test/OpenMP/parallel_private_codegen.cpp new file mode 100644 index 0000000000..2db06740d3 --- /dev/null +++ b/test/OpenMP/parallel_private_codegen.cpp @@ -0,0 +1,109 @@ +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// expected-no-diagnostics +#ifndef HEADER +#define HEADER + +template +struct S { + T f; + S(T a) : f(a) {} + S() : f() {} + operator T() { return T(); } + ~S() {} +}; + +// CHECK: [[S_FLOAT_TY:%.+]] = type { float } +// CHECK: [[CAP_MAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]* } +// CHECK: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} } +// CHECK: [[CAP_TMAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* } +// CHECK: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8* +template +T tmain() { + S test; + T t_var; + T vec[] = {1, 2}; + S s_arr[] = {1, 2}; + S var(3); +#pragma omp parallel private(t_var, vec, s_arr, var) + { + vec[0] = t_var; + s_arr[0] = var; + } + return T(); +} + +int main() { + S test; + int t_var; + int vec[] = {1, 2}; + S s_arr[] = {1, 2}; + S var(3); +#pragma omp parallel private(t_var, vec, s_arr, var) + { + vec[0] = t_var; + s_arr[0] = var; + } + return tmain(); +} + +// CHECK: define i{{[0-9]+}} @main() +// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]], +// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]]) +// CHECK: %{{.+}} = bitcast [[CAP_MAIN_TY]]* +// 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]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void +// CHECK: = call i{{.+}} [[TMAIN_INT:@.+]]() +// CHECK: call void [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]* +// CHECK: ret +// +// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_MAIN_TY]]* %{{.+}}) +// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}}, +// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}], +// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]], +// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]], +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]] +// CHECK-NOT: [[T_VAR_PRIV]] +// CHECK-NOT: [[VEC_PRIV]] +// CHECK: {{.+}}: +// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_FLOAT_TY]]* +// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[S_ARR_PRIV_ITEM]]) +// CHECK-NOT: [[T_VAR_PRIV]] +// CHECK-NOT: [[VEC_PRIV]] +// CHECK: call {{.*}} [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]]) +// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_REF]] +// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_REF]] +// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]]) +// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]]) +// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* +// CHECK: ret void + +// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]() +// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]], +// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]]) +// 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]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void +// CHECK: call void [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]* +// CHECK: ret +// +// CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_TMAIN_TY]]* %{{.+}}) +// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}}, +// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}], +// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]], +// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]], +// CHECK: store i{{[0-9]+}}* [[GTID_ADDR]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]] +// CHECK-NOT: [[T_VAR_PRIV]] +// CHECK-NOT: [[VEC_PRIV]] +// CHECK: {{.+}}: +// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_INT_TY]]* +// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[S_ARR_PRIV_ITEM]]) +// CHECK-NOT: [[T_VAR_PRIV]] +// CHECK-NOT: [[VEC_PRIV]] +// CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]]) +// CHECK: [[GTID_REF:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_REF]] +// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_REF]] +// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]]) +// 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 +#endif + diff --git a/test/OpenMP/parallel_private_messages.cpp b/test/OpenMP/parallel_private_messages.cpp index 1cd86d2b5f..14c5cbdb8a 100644 --- a/test/OpenMP/parallel_private_messages.cpp +++ b/test/OpenMP/parallel_private_messages.cpp @@ -25,15 +25,15 @@ public: const S3 c; // expected-note {{global variable is predetermined as shared}} const S3 ca[5]; // expected-note {{global variable is predetermined as shared}} extern const int f; // expected-note {{global variable is predetermined as shared}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v):a(v) { } }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5():a(0) {} + S5():a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v):a(v) { } }; @@ -44,8 +44,8 @@ int threadvar; int main(int argc, char **argv) { const int d = 5; // expected-note {{constant variable is predetermined as shared}} const int da[5] = { 0 }; // expected-note {{constant variable is predetermined as shared}} - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g[] = {5, 6}; int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel private // expected-error {{expected '(' after 'private'}} @@ -62,7 +62,7 @@ int main(int argc, char **argv) { #pragma omp parallel private(ca) // expected-error {{shared variable cannot be private}} #pragma omp parallel private(da) // expected-error {{shared variable cannot be private}} #pragma omp parallel private(S2::S2s) // expected-error {{shared variable cannot be private}} - #pragma omp parallel private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + #pragma omp parallel private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} #pragma omp parallel private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}} #pragma omp parallel shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}} foo(); diff --git a/test/OpenMP/parallel_sections_private_messages.cpp b/test/OpenMP/parallel_sections_private_messages.cpp index 7d39c7e2c5..e0b7488e51 100644 --- a/test/OpenMP/parallel_sections_private_messages.cpp +++ b/test/OpenMP/parallel_sections_private_messages.cpp @@ -24,16 +24,16 @@ public: S3() : a(0) {} }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -124,8 +124,8 @@ int foomain(I argc, C **argv) { } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp parallel sections private // expected-error {{expected '(' after 'private'}} @@ -168,7 +168,7 @@ int main(int argc, char **argv) { { foo(); } -#pragma omp parallel sections private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp parallel sections private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} { foo(); } diff --git a/test/OpenMP/sections_private_messages.cpp b/test/OpenMP/sections_private_messages.cpp index 7f5aa84968..8b330bf710 100644 --- a/test/OpenMP/sections_private_messages.cpp +++ b/test/OpenMP/sections_private_messages.cpp @@ -24,16 +24,16 @@ public: S3() : a(0) {} }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -124,8 +124,8 @@ int foomain(I argc, C **argv) { } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp sections private // expected-error {{expected '(' after 'private'}} @@ -168,7 +168,7 @@ int main(int argc, char **argv) { { foo(); } -#pragma omp sections private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp sections private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} { foo(); } diff --git a/test/OpenMP/simd_private_messages.cpp b/test/OpenMP/simd_private_messages.cpp index e5e4fe5b8b..56922e888b 100644 --- a/test/OpenMP/simd_private_messages.cpp +++ b/test/OpenMP/simd_private_messages.cpp @@ -22,15 +22,15 @@ public: S3():a(0) { } }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v):a(v) { } }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5():a(0) {} + S5():a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v):a(v) { } }; @@ -86,8 +86,8 @@ template int foomain(I argc, C **argv) { } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp simd private // expected-error {{expected '(' after 'private'}} @@ -110,7 +110,7 @@ int main(int argc, char **argv) { for (int k = 0; k < argc; ++k) ++k; #pragma omp simd private (argv[1]) // expected-error {{expected variable name}} for (int k = 0; k < argc; ++k) ++k; - #pragma omp simd private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + #pragma omp simd private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} for (int k = 0; k < argc; ++k) ++k; #pragma omp simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}} for (int k = 0; k < argc; ++k) ++k; diff --git a/test/OpenMP/single_private_messages.cpp b/test/OpenMP/single_private_messages.cpp index 1414a92ee0..8bdc48f1a5 100644 --- a/test/OpenMP/single_private_messages.cpp +++ b/test/OpenMP/single_private_messages.cpp @@ -24,16 +24,16 @@ public: S3() : a(0) {} }; const S3 ca[5]; -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -92,8 +92,8 @@ int foomain(I argc, C **argv) { } int main(int argc, char **argv) { - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp single private // expected-error {{expected '(' after 'private'}} @@ -116,7 +116,7 @@ int main(int argc, char **argv) { foo(); #pragma omp single private(argv[1]) // expected-error {{expected variable name}} foo(); -#pragma omp single private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp single private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} foo(); #pragma omp single private(h) // expected-error {{threadprivate or thread local variable cannot be private}} foo(); diff --git a/test/OpenMP/task_private_messages.cpp b/test/OpenMP/task_private_messages.cpp index 0be238dd90..9a3bb75768 100644 --- a/test/OpenMP/task_private_messages.cpp +++ b/test/OpenMP/task_private_messages.cpp @@ -27,16 +27,16 @@ public: const S3 c; // expected-note {{global variable is predetermined as shared}} const S3 ca[5]; // expected-note {{global variable is predetermined as shared}} extern const int f; // expected-note {{global variable is predetermined as shared}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v) : a(v) {} }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5() : a(0) {} + S5() : a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v) : a(v) {} @@ -48,8 +48,8 @@ int threadvar; int main(int argc, char **argv) { const int d = 5; // expected-note {{constant variable is predetermined as shared}} const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}} - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp task private // expected-error {{expected '(' after 'private'}} @@ -66,7 +66,7 @@ int main(int argc, char **argv) { #pragma omp task private(ca) // expected-error {{shared variable cannot be private}} #pragma omp task private(da) // expected-error {{shared variable cannot be private}} #pragma omp task private(S2::S2s) // expected-error {{shared variable cannot be private}} -#pragma omp task private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} +#pragma omp task private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} #pragma omp task private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}} #pragma omp task shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}} foo(); diff --git a/test/OpenMP/teams_private_messages.cpp b/test/OpenMP/teams_private_messages.cpp index c461b26e26..16ecb74ea0 100644 --- a/test/OpenMP/teams_private_messages.cpp +++ b/test/OpenMP/teams_private_messages.cpp @@ -25,15 +25,15 @@ public: const S3 c; // expected-note {{global variable is predetermined as shared}} const S3 ca[5]; // expected-note {{global variable is predetermined as shared}} extern const int f; // expected-note {{global variable is predetermined as shared}} -class S4 { // expected-note {{'S4' declared here}} +class S4 { int a; - S4(); + S4(); // expected-note {{implicitly declared private here}} public: S4(int v):a(v) { } }; -class S5 { // expected-note {{'S5' declared here}} +class S5 { int a; - S5():a(0) {} + S5():a(0) {} // expected-note {{implicitly declared private here}} public: S5(int v):a(v) { } }; @@ -44,8 +44,8 @@ int threadvar; int main(int argc, char **argv) { const int d = 5; // expected-note {{constant variable is predetermined as shared}} const int da[5] = { 0 }; // expected-note {{constant variable is predetermined as shared}} - S4 e(4); // expected-note {{'e' defined here}} - S5 g(5); // expected-note {{'g' defined here}} + S4 e(4); + S5 g(5); int i; int &j = i; // expected-note {{'j' defined here}} #pragma omp target @@ -91,7 +91,7 @@ int main(int argc, char **argv) { #pragma omp teams private(S2::S2s) // expected-error {{shared variable cannot be private}} foo(); #pragma omp target - #pragma omp teams private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + #pragma omp teams private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}} foo(); #pragma omp target #pragma omp teams private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index c497865bef..e96bb1cb89 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -2004,12 +2004,16 @@ void OMPClauseEnqueue::VisitOMPSeqCstClause(const OMPSeqCstClause *) {} template void OMPClauseEnqueue::VisitOMPClauseList(T *Node) { - for (const auto *I : Node->varlists()) + for (const auto *I : Node->varlists()) { Visitor->AddStmt(I); + } } void OMPClauseEnqueue::VisitOMPPrivateClause(const OMPPrivateClause *C) { VisitOMPClauseList(C); + for (const auto *E : C->private_copies()) { + Visitor->AddStmt(E); + } } void OMPClauseEnqueue::VisitOMPFirstprivateClause( const OMPFirstprivateClause *C) {