r232932 - [OPENMP] Codegen for 'copyprivate' clause ('single' directive).
Alexey Bataev
a.bataev at hotmail.com
Sun Mar 22 23:18:07 PDT 2015
Author: abataev
Date: Mon Mar 23 01:18:07 2015
New Revision: 232932
URL: http://llvm.org/viewvc/llvm-project?rev=232932&view=rev
Log:
[OPENMP] Codegen for 'copyprivate' clause ('single' directive).
If there is at least one 'copyprivate' clause is associated with the single directive, the following code is generated:
```
i32 did_it = 0; \\ for 'copyprivate' clause
if(__kmpc_single(ident_t *, gtid)) {
SingleOpGen();
__kmpc_end_single(ident_t *, gtid);
did_it = 1; \\ for 'copyprivate' clause
}
<copyprivate_list>[0] = &var0;
...
<copyprivate_list>[n] = &varn;
call __kmpc_copyprivate(ident_t *, gtid, <copyprivate_list_size>,
<copyprivate_list>, <copy_func>, did_it);
...
void<copy_func>(void *LHSArg, void *RHSArg) {
Dst = (void * [n])(LHSArg);
Src = (void * [n])(RHSArg);
Dst[0] = Src[0];
... Dst[n] = Src[n];
}
```
All list items from all 'copyprivate' clauses are gathered into single <copyprivate list> (<copyprivate_list_size> is a size in bytes of this list) and <copy_func> is used to propagate values of private or threadprivate variables from the 'single' region to other implicit threads from outer 'parallel' region.
Differential Revision: http://reviews.llvm.org/D8410
Modified:
cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h
cfe/trunk/include/clang/AST/OpenMPClause.h
cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
cfe/trunk/lib/AST/Stmt.cpp
cfe/trunk/lib/AST/StmtProfile.cpp
cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp
cfe/trunk/lib/CodeGen/CGOpenMPRuntime.h
cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/lib/Sema/SemaOpenMP.cpp
cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
cfe/trunk/test/OpenMP/single_codegen.cpp
cfe/trunk/test/OpenMP/single_copyprivate_messages.cpp
cfe/trunk/tools/libclang/CIndex.cpp
Modified: cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/DataRecursiveASTVisitor.h Mon Mar 23 01:18:07 2015
@@ -2562,6 +2562,15 @@ template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPCopyprivateClause(
OMPCopyprivateClause *C) {
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->source_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->destination_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->assignment_ops()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
Modified: cfe/trunk/include/clang/AST/OpenMPClause.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/OpenMPClause.h?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/OpenMPClause.h (original)
+++ cfe/trunk/include/clang/AST/OpenMPClause.h Mon Mar 23 01:18:07 2015
@@ -1674,6 +1674,7 @@ public:
/// with the variables 'a' and 'b'.
///
class OMPCopyprivateClause : public OMPVarListClause<OMPCopyprivateClause> {
+ friend class OMPClauseReader;
/// \brief Build clause with number of variables \a N.
///
/// \param StartLoc Starting location of the clause.
@@ -1695,6 +1696,46 @@ class OMPCopyprivateClause : public OMPV
OMPC_copyprivate, SourceLocation(), SourceLocation(),
SourceLocation(), N) {}
+ /// \brief Set list of helper expressions, required for proper codegen of the
+ /// clause. These expressions represent source expression in the final
+ /// assignment statement performed by the copyprivate clause.
+ void setSourceExprs(ArrayRef<Expr *> SrcExprs);
+
+ /// \brief Get the list of helper source expressions.
+ MutableArrayRef<Expr *> getSourceExprs() {
+ return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getSourceExprs() const {
+ return llvm::makeArrayRef(varlist_end(), varlist_size());
+ }
+
+ /// \brief Set list of helper expressions, required for proper codegen of the
+ /// clause. These expressions represent destination expression in the final
+ /// assignment statement performed by the copyprivate clause.
+ void setDestinationExprs(ArrayRef<Expr *> DstExprs);
+
+ /// \brief Get the list of helper destination expressions.
+ MutableArrayRef<Expr *> getDestinationExprs() {
+ return MutableArrayRef<Expr *>(getSourceExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getDestinationExprs() const {
+ return llvm::makeArrayRef(getSourceExprs().end(), varlist_size());
+ }
+
+ /// \brief Set list of helper assignment expressions, required for proper
+ /// codegen of the clause. These expressions are assignment expressions that
+ /// assign source helper expressions to destination helper expressions
+ /// correspondingly.
+ void setAssignmentOps(ArrayRef<Expr *> AssignmentOps);
+
+ /// \brief Get the list of helper assignment expressions.
+ MutableArrayRef<Expr *> getAssignmentOps() {
+ return MutableArrayRef<Expr *>(getDestinationExprs().end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getAssignmentOps() const {
+ return llvm::makeArrayRef(getDestinationExprs().end(), varlist_size());
+ }
+
public:
/// \brief Creates clause with a list of variables \a VL.
///
@@ -1703,10 +1744,24 @@ public:
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param VL List of references to the variables.
+ /// \param SrcExprs List of helper expressions for proper generation of
+ /// assignment operation required for copyprivate clause. This list represents
+ /// sources.
+ /// \param DstExprs List of helper expressions for proper generation of
+ /// assignment operation required for copyprivate clause. This list represents
+ /// destinations.
+ /// \param AsignmentOps List of helper expressions that represents assignment
+ /// operation:
+ /// \code
+ /// DstExprs = SrcExprs;
+ /// \endcode
+ /// Required for proper codegen of final assignment performed by the
+ /// copyprivate clause.
///
static OMPCopyprivateClause *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation EndLoc, ArrayRef<Expr *> VL);
+ SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
+ ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps);
/// \brief Creates an empty clause with \a N variables.
///
/// \param C AST context.
@@ -1714,6 +1769,36 @@ public:
///
static OMPCopyprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
+ typedef MutableArrayRef<Expr *>::iterator helper_expr_iterator;
+ typedef ArrayRef<const Expr *>::iterator helper_expr_const_iterator;
+ typedef llvm::iterator_range<helper_expr_iterator> helper_expr_range;
+ typedef llvm::iterator_range<helper_expr_const_iterator>
+ helper_expr_const_range;
+
+ helper_expr_const_range source_exprs() const {
+ return helper_expr_const_range(getSourceExprs().begin(),
+ getSourceExprs().end());
+ }
+ helper_expr_range source_exprs() {
+ return helper_expr_range(getSourceExprs().begin(), getSourceExprs().end());
+ }
+ helper_expr_const_range destination_exprs() const {
+ return helper_expr_const_range(getDestinationExprs().begin(),
+ getDestinationExprs().end());
+ }
+ helper_expr_range destination_exprs() {
+ return helper_expr_range(getDestinationExprs().begin(),
+ getDestinationExprs().end());
+ }
+ helper_expr_const_range assignment_ops() const {
+ return helper_expr_const_range(getAssignmentOps().begin(),
+ getAssignmentOps().end());
+ }
+ helper_expr_range assignment_ops() {
+ return helper_expr_range(getAssignmentOps().begin(),
+ getAssignmentOps().end());
+ }
+
StmtRange children() {
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
reinterpret_cast<Stmt **>(varlist_end()));
Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Mon Mar 23 01:18:07 2015
@@ -2592,6 +2592,15 @@ template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPCopyprivateClause(
OMPCopyprivateClause *C) {
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->source_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->destination_exprs()) {
+ TRY_TO(TraverseStmt(E));
+ }
+ for (auto *E : C->assignment_ops()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
Modified: cfe/trunk/lib/AST/Stmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Stmt.cpp?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Stmt.cpp (original)
+++ cfe/trunk/lib/AST/Stmt.cpp Mon Mar 23 01:18:07 2015
@@ -1388,17 +1388,41 @@ OMPCopyinClause *OMPCopyinClause::Create
return new (Mem) OMPCopyinClause(N);
}
-OMPCopyprivateClause *OMPCopyprivateClause::Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc,
- ArrayRef<Expr *> VL) {
+void OMPCopyprivateClause::setSourceExprs(ArrayRef<Expr *> SrcExprs) {
+ assert(SrcExprs.size() == varlist_size() && "Number of source expressions is "
+ "not the same as the "
+ "preallocated buffer");
+ std::copy(SrcExprs.begin(), SrcExprs.end(), varlist_end());
+}
+
+void OMPCopyprivateClause::setDestinationExprs(ArrayRef<Expr *> DstExprs) {
+ assert(DstExprs.size() == varlist_size() && "Number of destination "
+ "expressions is not the same as "
+ "the preallocated buffer");
+ std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end());
+}
+
+void OMPCopyprivateClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) {
+ assert(AssignmentOps.size() == varlist_size() &&
+ "Number of assignment expressions is not the same as the preallocated "
+ "buffer");
+ std::copy(AssignmentOps.begin(), AssignmentOps.end(),
+ getDestinationExprs().end());
+}
+
+OMPCopyprivateClause *OMPCopyprivateClause::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs,
+ ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * VL.size());
+ 4 * sizeof(Expr *) * VL.size());
OMPCopyprivateClause *Clause =
new (Mem) OMPCopyprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
+ Clause->setSourceExprs(SrcExprs);
+ Clause->setDestinationExprs(DstExprs);
+ Clause->setAssignmentOps(AssignmentOps);
return Clause;
}
@@ -1406,7 +1430,7 @@ OMPCopyprivateClause *OMPCopyprivateClau
unsigned N) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * N);
+ 4 * sizeof(Expr *) * N);
return new (Mem) OMPCopyprivateClause(N);
}
Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Mon Mar 23 01:18:07 2015
@@ -381,6 +381,15 @@ void OMPClauseProfiler::VisitOMPCopyinCl
void
OMPClauseProfiler::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) {
VisitOMPClauseList(C);
+ for (auto *E : C->source_exprs()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->destination_exprs()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->assignment_ops()) {
+ Profiler->VisitStmt(E);
+ }
}
void OMPClauseProfiler::VisitOMPFlushClause(const OMPFlushClause *C) {
VisitOMPClauseList(C);
Modified: cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp Mon Mar 23 01:18:07 2015
@@ -580,6 +580,21 @@ CGOpenMPRuntime::createRuntimeFunction(O
RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_omp_task");
break;
}
+ case OMPRTL__kmpc_copyprivate: {
+ // Build void __kmpc_copyprivate(ident_t *loc, kmp_int32 global_tid,
+ // kmp_int32 cpy_size, void *cpy_data, void(*cpy_func)(void *, void *),
+ // kmp_int32 didit);
+ llvm::Type *CpyTypeParams[] = {CGM.VoidPtrTy, CGM.VoidPtrTy};
+ auto *CpyFnTy =
+ llvm::FunctionType::get(CGM.VoidTy, CpyTypeParams, /*isVarArg=*/false);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty, CGM.Int32Ty,
+ CGM.VoidPtrTy, CpyFnTy->getPointerTo(),
+ CGM.Int32Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg=*/false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name=*/"__kmpc_copyprivate");
+ break;
+ }
}
return RTLFn;
}
@@ -965,19 +980,107 @@ void CGOpenMPRuntime::emitTaskyieldCall(
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_omp_taskyield), Args);
}
+static llvm::Value *emitCopyprivateCopyFunction(
+ CodeGenModule &CGM, llvm::Type *ArgsType, ArrayRef<const Expr *> SrcExprs,
+ ArrayRef<const Expr *> DstExprs, ArrayRef<const Expr *> AssignmentOps) {
+ auto &C = CGM.getContext();
+ // void copy_func(void *LHSArg, void *RHSArg);
+ FunctionArgList Args;
+ ImplicitParamDecl LHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
+ C.VoidPtrTy);
+ ImplicitParamDecl RHSArg(C, /*DC=*/nullptr, SourceLocation(), /*Id=*/nullptr,
+ C.VoidPtrTy);
+ Args.push_back(&LHSArg);
+ Args.push_back(&RHSArg);
+ FunctionType::ExtInfo EI;
+ auto &CGFI = CGM.getTypes().arrangeFreeFunctionDeclaration(
+ C.VoidTy, Args, EI, /*isVariadic=*/false);
+ auto *Fn = llvm::Function::Create(
+ CGM.getTypes().GetFunctionType(CGFI), llvm::GlobalValue::InternalLinkage,
+ ".omp.copyprivate.copy_func", &CGM.getModule());
+ CGM.SetLLVMFunctionAttributes(/*D=*/nullptr, CGFI, Fn);
+ CodeGenFunction CGF(CGM);
+ CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, CGFI, Args);
+ // Dst = (void*[n])(LHSArg);
+ // Src = (void*[n])(RHSArg);
+ auto *LHS = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(CGF.GetAddrOfLocalVar(&LHSArg),
+ CGF.PointerAlignInBytes),
+ ArgsType);
+ auto *RHS = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(CGF.GetAddrOfLocalVar(&RHSArg),
+ CGF.PointerAlignInBytes),
+ ArgsType);
+ // *(Type0*)Dst[0] = *(Type0*)Src[0];
+ // *(Type1*)Dst[1] = *(Type1*)Src[1];
+ // ...
+ // *(Typen*)Dst[n] = *(Typen*)Src[n];
+ CodeGenFunction::OMPPrivateScope Scope(CGF);
+ for (unsigned I = 0, E = AssignmentOps.size(); I < E; ++I) {
+ Scope.addPrivate(
+ cast<VarDecl>(cast<DeclRefExpr>(SrcExprs[I])->getDecl()),
+ [&]() -> llvm::Value *{
+ return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(CGF.Builder.CreateStructGEP(RHS, I),
+ CGM.PointerAlignInBytes),
+ CGF.ConvertTypeForMem(C.getPointerType(SrcExprs[I]->getType())));
+ });
+ Scope.addPrivate(
+ cast<VarDecl>(cast<DeclRefExpr>(DstExprs[I])->getDecl()),
+ [&]() -> llvm::Value *{
+ return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.Builder.CreateAlignedLoad(CGF.Builder.CreateStructGEP(LHS, I),
+ CGM.PointerAlignInBytes),
+ CGF.ConvertTypeForMem(C.getPointerType(SrcExprs[I]->getType())));
+ });
+ }
+ Scope.Privatize();
+ for (auto *E : AssignmentOps) {
+ CGF.EmitIgnoredExpr(E);
+ }
+ Scope.ForceCleanup();
+ CGF.FinishFunction();
+ return Fn;
+}
+
void CGOpenMPRuntime::emitSingleRegion(CodeGenFunction &CGF,
const std::function<void()> &SingleOpGen,
- SourceLocation Loc) {
+ SourceLocation Loc,
+ ArrayRef<const Expr *> CopyprivateVars,
+ ArrayRef<const Expr *> SrcExprs,
+ ArrayRef<const Expr *> DstExprs,
+ ArrayRef<const Expr *> AssignmentOps) {
+ assert(CopyprivateVars.size() == SrcExprs.size() &&
+ CopyprivateVars.size() == DstExprs.size() &&
+ CopyprivateVars.size() == AssignmentOps.size());
+ auto &C = CGM.getContext();
+ // int32 did_it = 0;
// if(__kmpc_single(ident_t *, gtid)) {
// SingleOpGen();
// __kmpc_end_single(ident_t *, gtid);
+ // did_it = 1;
// }
+ // call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
+ // <copy_func>, did_it);
+
+ llvm::AllocaInst *DidIt = nullptr;
+ if (!CopyprivateVars.empty()) {
+ // int32 did_it = 0;
+ auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
+ DidIt = CGF.CreateMemTemp(KmpInt32Ty, ".omp.copyprivate.did_it");
+ CGF.InitTempAlloca(DidIt, CGF.Builder.getInt32(0));
+ }
// Prepare arguments and build a call to __kmpc_single
llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)};
auto *IsSingle =
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_single), Args);
emitIfStmt(CGF, IsSingle, [&]() -> void {
SingleOpGen();
+ if (DidIt) {
+ // did_it = 1;
+ CGF.Builder.CreateAlignedStore(CGF.Builder.getInt32(1), DidIt,
+ DidIt->getAlignment());
+ }
// Build a call to __kmpc_end_single.
// OpenMP [1.2.2 OpenMP Language Terminology]
// For C/C++, an executable statement, possibly compound, with a single
@@ -994,6 +1097,44 @@ void CGOpenMPRuntime::emitSingleRegion(C
// fallthrough rather than pushing a normal cleanup for it.
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_end_single), Args);
});
+ // call __kmpc_copyprivate(ident_t *, gtid, <buf_size>, <copyprivate list>,
+ // <copy_func>, did_it);
+ if (DidIt) {
+ llvm::APInt ArraySize(/*unsigned int numBits=*/32, CopyprivateVars.size());
+ auto CopyprivateArrayTy =
+ C.getConstantArrayType(C.VoidPtrTy, ArraySize, ArrayType::Normal,
+ /*IndexTypeQuals=*/0);
+ // Create a list of all private variables for copyprivate.
+ auto *CopyprivateList =
+ CGF.CreateMemTemp(CopyprivateArrayTy, ".omp.copyprivate.cpr_list");
+ for (unsigned I = 0, E = CopyprivateVars.size(); I < E; ++I) {
+ auto *Elem = CGF.Builder.CreateStructGEP(CopyprivateList, I);
+ CGF.Builder.CreateAlignedStore(
+ CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
+ CGF.EmitLValue(CopyprivateVars[I]).getAddress(), CGF.VoidPtrTy),
+ Elem, CGM.PointerAlignInBytes);
+ }
+ // Build function that copies private values from single region to all other
+ // threads in the corresponding parallel region.
+ auto *CpyFn = emitCopyprivateCopyFunction(
+ CGM, CGF.ConvertTypeForMem(CopyprivateArrayTy)->getPointerTo(),
+ SrcExprs, DstExprs, AssignmentOps);
+ auto *BufSize = CGF.Builder.getInt32(
+ C.getTypeSizeInChars(CopyprivateArrayTy).getQuantity());
+ auto *CL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(CopyprivateList,
+ CGF.VoidPtrTy);
+ auto *DidItVal =
+ CGF.Builder.CreateAlignedLoad(DidIt, CGF.PointerAlignInBytes);
+ llvm::Value *Args[] = {
+ emitUpdateLocation(CGF, Loc), // ident_t *<loc>
+ getThreadID(CGF, Loc), // i32 <gtid>
+ BufSize, // i32 <buf_size>
+ CL, // void *<copyprivate list>
+ CpyFn, // void (*) (void *, void *) <copy_func>
+ DidItVal // i32 did_it
+ };
+ CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_copyprivate), Args);
+ }
}
void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
Modified: cfe/trunk/lib/CodeGen/CGOpenMPRuntime.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGOpenMPRuntime.h?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGOpenMPRuntime.h (original)
+++ cfe/trunk/lib/CodeGen/CGOpenMPRuntime.h Mon Mar 23 01:18:07 2015
@@ -96,6 +96,10 @@ class CGOpenMPRuntime {
// Call to kmp_int32 __kmpc_omp_task(ident_t *, kmp_int32 gtid, kmp_task_t *
// new_task);
OMPRTL__kmpc_omp_task,
+ // Call to void __kmpc_copyprivate(ident_t *loc, kmp_int32 global_tid,
+ // kmp_int32 cpy_size, void *cpy_data, void(*cpy_func)(void *, void *),
+ // kmp_int32 didit);
+ OMPRTL__kmpc_copyprivate,
};
/// \brief Values for bit flags used in the ident_t to describe the fields.
@@ -348,7 +352,11 @@ public:
/// single region.
virtual void emitSingleRegion(CodeGenFunction &CGF,
const std::function<void()> &SingleOpGen,
- SourceLocation Loc);
+ SourceLocation Loc,
+ ArrayRef<const Expr *> CopyprivateVars,
+ ArrayRef<const Expr *> SrcExprs,
+ ArrayRef<const Expr *> DstExprs,
+ ArrayRef<const Expr *> AssignmentOps);
/// \brief Emits explicit barrier for OpenMP threads.
/// \param IsExplicit true, if it is explicitly specified barrier.
Modified: cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp Mon Mar 23 01:18:07 2015
@@ -882,7 +882,7 @@ void CodeGenFunction::EmitOMPSectionsDir
InlinedOpenMPRegionScopeRAII Region(*this, S);
EmitStmt(Stmt);
EnsureInsertPoint();
- }, S.getLocStart());
+ }, S.getLocStart(), llvm::None, llvm::None, llvm::None, llvm::None);
}
// Emit an implicit barrier at the end.
@@ -898,11 +898,38 @@ void CodeGenFunction::EmitOMPSectionDire
}
void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) {
+ llvm::SmallVector<const Expr *, 8> CopyprivateVars;
+ llvm::SmallVector<const Expr *, 8> SrcExprs;
+ llvm::SmallVector<const Expr *, 8> DstExprs;
+ llvm::SmallVector<const Expr *, 8> AssignmentOps;
+ // Check if there are any 'copyprivate' clauses associated with this 'single'
+ // construct.
+ auto CopyprivateFilter = [](const OMPClause *C) -> bool {
+ return C->getClauseKind() == OMPC_copyprivate;
+ };
+ // Build a list of copyprivate variables along with helper expressions
+ // (<source>, <destination>, <destination>=<source> expressions)
+ typedef OMPExecutableDirective::filtered_clause_iterator<decltype(
+ CopyprivateFilter)> CopyprivateIter;
+ for (CopyprivateIter I(S.clauses(), CopyprivateFilter); I; ++I) {
+ auto *C = cast<OMPCopyprivateClause>(*I);
+ CopyprivateVars.append(C->varlists().begin(), C->varlists().end());
+ SrcExprs.append(C->source_exprs().begin(), C->source_exprs().end());
+ DstExprs.append(C->destination_exprs().begin(),
+ C->destination_exprs().end());
+ AssignmentOps.append(C->assignment_ops().begin(),
+ C->assignment_ops().end());
+ }
+ // Emit code for 'single' region along with 'copyprivate' clauses
CGM.getOpenMPRuntime().emitSingleRegion(*this, [&]() -> void {
InlinedOpenMPRegionScopeRAII Region(*this, S);
EmitStmt(cast<CapturedStmt>(S.getAssociatedStmt())->getCapturedStmt());
EnsureInsertPoint();
- }, S.getLocStart());
+ }, S.getLocStart(), CopyprivateVars, SrcExprs, DstExprs, AssignmentOps);
+ // Emit an implicit barrier at the end.
+ if (!S.getSingleClause(OMPC_nowait))
+ CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(),
+ /*IsExplicit=*/false);
}
void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Mon Mar 23 01:18:07 2015
@@ -604,7 +604,10 @@ public:
}
/// \brief Exit scope - all the mapped variables are restored.
- ~OMPPrivateScope() { ForceCleanup(); }
+ ~OMPPrivateScope() {
+ if (PerformCleanup)
+ ForceCleanup();
+ }
};
/// \brief Takes the old cleanup stack size and emits the cleanup blocks
Modified: cfe/trunk/lib/Sema/SemaOpenMP.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOpenMP.cpp?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOpenMP.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOpenMP.cpp Mon Mar 23 01:18:07 2015
@@ -5614,11 +5614,17 @@ OMPClause *Sema::ActOnOpenMPCopyprivateC
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
+ SmallVector<Expr *, 8> SrcExprs;
+ SmallVector<Expr *, 8> DstExprs;
+ SmallVector<Expr *, 8> AssignmentOps;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP copyprivate clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
+ SrcExprs.push_back(nullptr);
+ DstExprs.push_back(nullptr);
+ AssignmentOps.push_back(nullptr);
continue;
}
@@ -5640,6 +5646,9 @@ OMPClause *Sema::ActOnOpenMPCopyprivateC
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
// It will be analyzed later.
Vars.push_back(DE);
+ SrcExprs.push_back(nullptr);
+ DstExprs.push_back(nullptr);
+ AssignmentOps.push_back(nullptr);
continue;
}
@@ -5648,8 +5657,8 @@ OMPClause *Sema::ActOnOpenMPCopyprivateC
// private or firstprivate clause on the single construct.
if (!DSAStack->isThreadPrivate(VD)) {
auto DVar = DSAStack->getTopDSA(VD, false);
- if (DVar.CKind != OMPC_copyprivate && DVar.CKind != OMPC_unknown &&
- !(DVar.CKind == OMPC_private && !DVar.RefExpr)) {
+ if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_copyprivate &&
+ DVar.RefExpr) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_copyprivate);
@@ -5676,41 +5685,36 @@ OMPClause *Sema::ActOnOpenMPCopyprivateC
// A variable of class type (or array thereof) that appears in a
// copyin clause requires an accessible, unambiguous copy assignment
// operator for the class type.
- Type = Context.getBaseElementType(Type);
- CXXRecordDecl *RD =
- getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr;
- // FIXME This code must be replaced by actual assignment of the
- // threadprivate variable.
- if (RD) {
- CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0);
- DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess());
- if (MD) {
- if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible ||
- MD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_copyprivate) << 2;
- 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, MD);
- DiagnoseUseOfDecl(MD, ELoc);
- }
- }
+ auto *SrcVD = BuildVarDecl(*this, DE->getLocStart(), VD->getType(),
+ ".copyprivate.src");
+ auto *PseudoSrcExpr = BuildDeclRefExpr(SrcVD, DE->getType(), VK_LValue,
+ DE->getExprLoc()).get();
+ auto *DstVD = BuildVarDecl(*this, DE->getLocStart(), VD->getType(),
+ ".copyprivate.dst");
+ auto *PseudoDstExpr = BuildDeclRefExpr(DstVD, DE->getType(), VK_LValue,
+ DE->getExprLoc()).get();
+ auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign,
+ PseudoDstExpr, PseudoSrcExpr);
+ if (AssignmentOp.isInvalid())
+ continue;
+ AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(),
+ /*DiscardedValue=*/true);
+ if (AssignmentOp.isInvalid())
+ continue;
// No need to mark vars as copyprivate, they are already threadprivate or
// implicitly private.
Vars.push_back(DE);
+ SrcExprs.push_back(PseudoSrcExpr);
+ DstExprs.push_back(PseudoDstExpr);
+ AssignmentOps.push_back(AssignmentOp.get());
}
if (Vars.empty())
return nullptr;
- return OMPCopyprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
+ return OMPCopyprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ Vars, SrcExprs, DstExprs, AssignmentOps);
}
OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList,
Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Mon Mar 23 01:18:07 2015
@@ -1969,11 +1969,23 @@ void OMPClauseReader::VisitOMPCopyinClau
void OMPClauseReader::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();
- SmallVector<Expr *, 16> Vars;
- Vars.reserve(NumVars);
+ SmallVector<Expr *, 16> Exprs;
+ Exprs.reserve(NumVars);
for (unsigned i = 0; i != NumVars; ++i)
- Vars.push_back(Reader->Reader.ReadSubExpr());
- C->setVarRefs(Vars);
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setVarRefs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setSourceExprs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setDestinationExprs(Exprs);
+ Exprs.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Exprs.push_back(Reader->Reader.ReadSubExpr());
+ C->setAssignmentOps(Exprs);
}
void OMPClauseReader::VisitOMPFlushClause(OMPFlushClause *C) {
Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Mon Mar 23 01:18:07 2015
@@ -1857,6 +1857,12 @@ void OMPClauseWriter::VisitOMPCopyprivat
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
for (auto *VE : C->varlists())
Writer->Writer.AddStmt(VE);
+ for (auto *E : C->source_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->destination_exprs())
+ Writer->Writer.AddStmt(E);
+ for (auto *E : C->assignment_ops())
+ Writer->Writer.AddStmt(E);
}
void OMPClauseWriter::VisitOMPFlushClause(OMPFlushClause *C) {
Modified: cfe/trunk/test/OpenMP/single_codegen.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/single_codegen.cpp?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/single_codegen.cpp (original)
+++ cfe/trunk/test/OpenMP/single_codegen.cpp Mon Mar 23 01:18:07 2015
@@ -7,19 +7,38 @@
#ifndef HEADER
#define HEADER
+class TestClass {
+public:
+ int a;
+ TestClass() : a(0) {}
+ TestClass(const TestClass &C) : a(C.a) {}
+ TestClass &operator=(const TestClass &) { return *this;}
+ ~TestClass(){};
+};
+
+// CHECK-DAG: [[TEST_CLASS_TY:%.+]] = type { i{{[0-9]+}} }
// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* }
// CHECK: define void [[FOO:@.+]]()
+TestClass tc;
+#pragma omp threadprivate(tc)
+
void foo() {}
// CHECK-LABEL: @main
// TERM_DEBUG-LABEL: @main
int main() {
- // CHECK: [[A_ADDR:%.+]] = alloca i8
+ // CHECK-DAG: [[A_ADDR:%.+]] = alloca i8
+ // CHECK-DAG: [[C_ADDR:%.+]] = alloca [[TEST_CLASS_TY]]
char a;
+ TestClass c;
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]])
+// CHECK-DAG: [[DID_IT:%.+]] = alloca i32,
+// CHECK-DAG: [[COPY_LIST:%.+]] = alloca [3 x i8*],
+// CHECK: store i32 0, i32* [[DID_IT]]
+
// CHECK: [[RES:%.+]] = call i32 @__kmpc_single([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
// CHECK-NEXT: [[IS_SINGLE:%.+]] = icmp ne i32 [[RES]], 0
// CHECK-NEXT: br i1 [[IS_SINGLE]], label {{%?}}[[THEN:.+]], label {{%?}}[[EXIT:.+]]
@@ -28,23 +47,69 @@ int main() {
// CHECK-NEXT: call void @__kmpc_end_single([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
// CHECK-NEXT: br label {{%?}}[[EXIT]]
// CHECK: [[EXIT]]
-#pragma omp single
+#pragma omp single nowait
a = 2;
// CHECK: [[RES:%.+]] = call i32 @__kmpc_single([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
// CHECK-NEXT: [[IS_SINGLE:%.+]] = icmp ne i32 [[RES]], 0
// CHECK-NEXT: br i1 [[IS_SINGLE]], label {{%?}}[[THEN:.+]], label {{%?}}[[EXIT:.+]]
// CHECK: [[THEN]]
// CHECK-NEXT: invoke void [[FOO]]()
+// CHECK: to label {{%?}}[[CONT:.+]] unwind
+// CHECK: [[CONT]]
+// CHECK: store i32 1, i32* [[DID_IT]]
// CHECK: call void @__kmpc_end_single([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]])
// CHECK-NEXT: br label {{%?}}[[EXIT]]
// CHECK: [[EXIT]]
-#pragma omp single
+// CHECK: [[A_PTR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[COPY_LIST]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: store i8* [[A_ADDR]], i8** [[A_PTR_REF]],
+// CHECK: [[C_PTR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[COPY_LIST]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[C_PTR_REF_VOID_PTR:%.+]] = bitcast [[TEST_CLASS_TY]]* [[C_ADDR]] to i8*
+// CHECK: store i8* [[C_PTR_REF_VOID_PTR]], i8** [[C_PTR_REF]],
+// CHECK: [[TC_PTR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[COPY_LIST]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[TC_THREADPRIVATE_ADDR_VOID_PTR:%.+]] = call{{.*}} i8* @__kmpc_threadprivate_cached
+// CHECK: [[TC_THREADPRIVATE_ADDR:%.+]] = bitcast i8* [[TC_THREADPRIVATE_ADDR_VOID_PTR]] to [[TEST_CLASS_TY]]*
+// CHECK: [[TC_PTR_REF_VOID_PTR:%.+]] = bitcast [[TEST_CLASS_TY]]* [[TC_THREADPRIVATE_ADDR]] to i8*
+// CHECK: store i8* [[TC_PTR_REF_VOID_PTR]], i8** [[TC_PTR_REF]],
+// CHECK: [[COPY_LIST_VOID_PTR:%.+]] = bitcast [3 x i8*]* [[COPY_LIST]] to i8*
+// CHECK: [[DID_IT_VAL:%.+]] = load i32, i32* [[DID_IT]],
+// CHECK: call void @__kmpc_copyprivate([[IDENT_T_TY]]* [[DEFAULT_LOC]], i32 [[GTID]], i32 24, i8* [[COPY_LIST_VOID_PTR]], void (i8*, i8*)* [[COPY_FUNC:@.+]], i32 [[DID_IT_VAL]])
+// CHECK: call{{.*}} @__kmpc_cancel_barrier([[IDENT_T_TY]]* {{@.+}}, i32 [[GTID]])
+#pragma omp single copyprivate(a, c, tc)
foo();
// CHECK-NOT: call i32 @__kmpc_single
// CHECK-NOT: call void @__kmpc_end_single
return a;
}
+// CHECK: void [[COPY_FUNC]](i8*, i8*)
+// CHECK: store i8* %0, i8** [[DST_ADDR_REF:%.+]],
+// CHECK: store i8* %1, i8** [[SRC_ADDR_REF:%.+]],
+// CHECK: [[DST_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[DST_ADDR_REF]],
+// CHECK: [[DST_ADDR:%.+]] = bitcast i8* [[DST_ADDR_VOID_PTR]] to [3 x i8*]*
+// CHECK: [[SRC_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[SRC_ADDR_REF]],
+// CHECK: [[SRC_ADDR:%.+]] = bitcast i8* [[SRC_ADDR_VOID_PTR]] to [3 x i8*]*
+// CHECK: [[SRC_A_ADDR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[SRC_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[SRC_A_ADDR:%.+]] = load i8*, i8** [[SRC_A_ADDR_REF]],
+// CHECK: [[DST_A_ADDR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[DST_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+// CHECK: [[DST_A_ADDR:%.+]] = load i8*, i8** [[DST_A_ADDR_REF]],
+// CHECK: [[SRC_C_ADDR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[SRC_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[SRC_C_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[SRC_C_ADDR_REF]],
+// CHECK: [[SRC_C_ADDR:%.+]] = bitcast i8* [[SRC_C_ADDR_VOID_PTR:%.+]] to [[TEST_CLASS_TY]]*
+// CHECK: [[DST_C_ADDR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[DST_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+// CHECK: [[DST_C_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[DST_C_ADDR_REF]],
+// CHECK: [[DST_C_ADDR:%.+]] = bitcast i8* [[DST_C_ADDR_VOID_PTR:%.+]] to [[TEST_CLASS_TY]]*
+// CHECK: [[SRC_TC_ADDR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[SRC_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[SRC_TC_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[SRC_TC_ADDR_REF]],
+// CHECK: [[SRC_TC_ADDR:%.+]] = bitcast i8* [[SRC_TC_ADDR_VOID_PTR:%.+]] to [[TEST_CLASS_TY]]*
+// CHECK: [[DST_TC_ADDR_REF:%.+]] = getelementptr inbounds [3 x i8*], [3 x i8*]* [[DST_ADDR]], i{{[0-9]+}} 0, i{{[0-9]+}} 2
+// CHECK: [[DST_TC_ADDR_VOID_PTR:%.+]] = load i8*, i8** [[DST_TC_ADDR_REF]],
+// CHECK: [[DST_TC_ADDR:%.+]] = bitcast i8* [[DST_TC_ADDR_VOID_PTR:%.+]] to [[TEST_CLASS_TY]]*
+// CHECK: [[SRC_A_VAL:%.+]] = load i8, i8* [[SRC_A_ADDR]],
+// CHECK: store i8 [[SRC_A_VAL]], i8* [[DST_A_ADDR]],
+// CHECK: call{{.*}} [[TEST_CLASS_TY_ASSIGN:@.+]]([[TEST_CLASS_TY]]* [[DST_C_ADDR]], [[TEST_CLASS_TY]]* {{.*}}[[SRC_C_ADDR]])
+// CHECK: call{{.*}} [[TEST_CLASS_TY_ASSIGN:@.+]]([[TEST_CLASS_TY]]* [[DST_TC_ADDR]], [[TEST_CLASS_TY]]* {{.*}}[[SRC_TC_ADDR]])
+// CHECK: ret void
+
// CHECK-LABEL: parallel_single
// TERM_DEBUG-LABEL: parallel_single
void parallel_single() {
@@ -61,7 +126,7 @@ void parallel_single() {
// TERM_DEBUG: unreachable
foo();
}
-// TERM_DEBUG-DAG: [[DBG_LOC_START]] = !MDLocation(line: 52,
-// TERM_DEBUG-DAG: [[DBG_LOC_END]] = !MDLocation(line: 52,
+// TERM_DEBUG-DAG: [[DBG_LOC_START]] = !MDLocation(line: [[@LINE-12]],
+// TERM_DEBUG-DAG: [[DBG_LOC_END]] = !MDLocation(line: [[@LINE-13]],
#endif
Modified: cfe/trunk/test/OpenMP/single_copyprivate_messages.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/single_copyprivate_messages.cpp?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/test/OpenMP/single_copyprivate_messages.cpp (original)
+++ cfe/trunk/test/OpenMP/single_copyprivate_messages.cpp Mon Mar 23 01:18:07 2015
@@ -18,18 +18,18 @@ public:
S3() : a(0) {}
S3 &operator=(S3 &s3) { return *this; }
};
-class S4 { // expected-note 2 {{'S4' declared here}}
+class S4 {
int a;
S4();
- S4 &operator=(const S4 &s4);
+ S4 &operator=(const S4 &s4); // expected-note 3 {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note 2 {{'S5' declared here}}
+class S5 {
int a;
S5() : a(0) {}
- S5 &operator=(const S5 &s5) { return *this; }
+ S5 &operator=(const S5 &s5) { return *this; } // expected-note 3 {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -37,8 +37,8 @@ public:
S2 k;
S3 h;
-S4 l(3); // expected-note 2 {{'l' defined here}}
-S5 m(4); // expected-note 2 {{'m' defined here}}
+S4 l(3);
+S5 m(4);
#pragma omp threadprivate(h, k, l, m)
template <class T, class C>
@@ -58,7 +58,7 @@ T tmain(T argc, C **argv) {
#pragma omp parallel
#pragma omp single copyprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
#pragma omp parallel
-#pragma omp single copyprivate(l) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp single copyprivate(l) // expected-error 2 {{'operator=' is a private member of 'S4'}}
#pragma omp parallel
#pragma omp single copyprivate(S1) // expected-error {{'S1' does not refer to a value}}
#pragma omp parallel
@@ -66,7 +66,7 @@ T tmain(T argc, C **argv) {
#pragma omp parallel // expected-note {{implicitly determined as shared}}
#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}}
#pragma omp parallel
-#pragma omp single copyprivate(m) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp single copyprivate(m) // expected-error 2 {{'operator=' is a private member of 'S5'}}
foo();
#pragma omp parallel private(i)
{
@@ -121,7 +121,7 @@ int main(int argc, char **argv) {
#pragma omp parallel
#pragma omp single copyprivate(argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}}
#pragma omp parallel
-#pragma omp single copyprivate(l) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp single copyprivate(l) // expected-error {{'operator=' is a private member of 'S4'}}
#pragma omp parallel
#pragma omp single copyprivate(S1) // expected-error {{'S1' does not refer to a value}}
#pragma omp parallel
@@ -129,7 +129,7 @@ int main(int argc, char **argv) {
#pragma omp parallel // expected-note {{implicitly determined as shared}}
#pragma omp single copyprivate(i) // expected-error {{copyprivate variable must be threadprivate or private in the enclosing context}}
#pragma omp parallel
-#pragma omp single copyprivate(m) // expected-error {{copyprivate variable must have an accessible, unambiguous copy assignment operator}}
+#pragma omp single copyprivate(m) // expected-error {{'operator=' is a private member of 'S5'}}
foo();
#pragma omp parallel private(i)
{
Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=232932&r1=232931&r2=232932&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Mon Mar 23 01:18:07 2015
@@ -2053,6 +2053,15 @@ void OMPClauseEnqueue::VisitOMPCopyinCla
void
OMPClauseEnqueue::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) {
VisitOMPClauseList(C);
+ for (auto *E : C->source_exprs()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->destination_exprs()) {
+ Visitor->AddStmt(E);
+ }
+ for (auto *E : C->assignment_ops()) {
+ Visitor->AddStmt(E);
+ }
}
void OMPClauseEnqueue::VisitOMPFlushClause(const OMPFlushClause *C) {
VisitOMPClauseList(C);
More information about the cfe-commits
mailing list