summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/Stmt.cpp34
-rw-r--r--clang/lib/AST/StmtProfile.cpp10
-rw-r--r--clang/lib/CodeGen/CGDecl.cpp2
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntime.cpp93
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntime.h111
-rw-r--r--clang/lib/CodeGen/CGStmtOpenMP.cpp119
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h13
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp146
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp8
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp9
10 files changed, 401 insertions, 144 deletions
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index af19af4943a..0d039939bc0 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -1198,19 +1198,31 @@ OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPPrivateClause(N);
}
-OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc,
- ArrayRef<Expr *> VL) {
+void OMPFirstprivateClause::setPrivateCopies(ArrayRef<Expr *> 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());
+}
+
+void OMPFirstprivateClause::setInits(ArrayRef<Expr *> VL) {
+ assert(VL.size() == varlist_size() &&
+ "Number of inits is not the same as the preallocated buffer");
+ std::copy(VL.begin(), VL.end(), getPrivateCopies().end());
+}
+
+OMPFirstprivateClause *
+OMPFirstprivateClause::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc,
+ ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL,
+ ArrayRef<Expr *> InitVL) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * VL.size());
- OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(StartLoc,
- LParenLoc,
- EndLoc,
- VL.size());
+ 3 * sizeof(Expr *) * VL.size());
+ OMPFirstprivateClause *Clause =
+ new (Mem) OMPFirstprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
+ Clause->setPrivateCopies(PrivateVL);
+ Clause->setInits(InitVL);
return Clause;
}
@@ -1218,7 +1230,7 @@ OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C,
unsigned N) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * N);
+ 3 * sizeof(Expr *) * N);
return new (Mem) OMPFirstprivateClause(N);
}
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 9bcb5929ed0..157e21d069b 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -329,9 +329,15 @@ void OMPClauseProfiler::VisitOMPClauseList(T *Node) {
void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) {
VisitOMPClauseList(C);
}
-void OMPClauseProfiler::VisitOMPFirstprivateClause(
- const OMPFirstprivateClause *C) {
+void
+OMPClauseProfiler::VisitOMPFirstprivateClause(const OMPFirstprivateClause *C) {
VisitOMPClauseList(C);
+ for (auto *E : C->private_copies()) {
+ Profiler->VisitStmt(E);
+ }
+ for (auto *E : C->inits()) {
+ Profiler->VisitStmt(E);
+ }
}
void
OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) {
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index d4a546dc112..24575ce6d41 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -1073,7 +1073,7 @@ static bool isCapturedBy(const VarDecl &var, const Expr *e) {
/// \brief Determine whether the given initializer is trivial in the sense
/// that it requires no code to be generated.
-static bool isTrivialInitializer(const Expr *Init) {
+bool CodeGenFunction::isTrivialInitializer(const Expr *Init) {
if (!Init)
return true;
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index 9dfcd0753b2..c439833cfe7 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -24,6 +24,29 @@
using namespace clang;
using namespace CodeGen;
+void CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF, Stmt *S) {
+ CodeGenFunction::OuterDeclMapTy OuterDeclMap;
+ CGF.EmitOMPFirstprivateClause(Directive, OuterDeclMap);
+ if (!OuterDeclMap.empty()) {
+ // Emit implicit barrier to synchronize threads and avoid data races.
+ auto Flags = static_cast<CGOpenMPRuntime::OpenMPLocationFlags>(
+ CGOpenMPRuntime::OMP_IDENT_KMPC |
+ CGOpenMPRuntime::OMP_IDENT_BARRIER_IMPL);
+ CGF.CGM.getOpenMPRuntime().EmitOMPBarrierCall(CGF, Directive.getLocStart(),
+ Flags);
+ // Remap captured variables to use their private copies in the outlined
+ // function.
+ for (auto I : OuterDeclMap) {
+ CGF.LocalDeclMap[I.first] = I.second;
+ }
+ }
+ CGCapturedStmtInfo::EmitBody(CGF, S);
+ // Clear mappings of captured private variables.
+ for (auto I : OuterDeclMap) {
+ CGF.LocalDeclMap.erase(I.first);
+ }
+}
+
CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM)
: CGM(CGM), DefaultOpenMPPSource(nullptr) {
IdentTy = llvm::StructType::create(
@@ -51,11 +74,10 @@ CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) {
DefaultOpenMPPSource =
llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy);
}
- llvm::GlobalVariable *DefaultOpenMPLocation = cast<llvm::GlobalVariable>(
- CGM.CreateRuntimeVariable(IdentTy, ".kmpc_default_loc.addr"));
+ auto DefaultOpenMPLocation = new llvm::GlobalVariable(
+ CGM.getModule(), IdentTy, /*isConstant*/ true,
+ llvm::GlobalValue::PrivateLinkage, /*Initializer*/ nullptr);
DefaultOpenMPLocation->setUnnamedAddr(true);
- DefaultOpenMPLocation->setConstant(true);
- DefaultOpenMPLocation->setLinkage(llvm::GlobalValue::PrivateLinkage);
llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true);
llvm::Constant *Values[] = {Zero,
@@ -63,6 +85,7 @@ CGOpenMPRuntime::GetOrCreateDefaultOpenMPLocation(OpenMPLocationFlags Flags) {
Zero, Zero, DefaultOpenMPPSource};
llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values);
DefaultOpenMPLocation->setInitializer(Init);
+ OpenMPDefaultLocMap[Flags] = DefaultOpenMPLocation;
return DefaultOpenMPLocation;
}
return Entry;
@@ -120,14 +143,14 @@ llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation(
return LocValue;
}
-llvm::Value *CGOpenMPRuntime::GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
- SourceLocation Loc) {
+llvm::Value *CGOpenMPRuntime::GetOpenMPThreadID(CodeGenFunction &CGF,
+ SourceLocation Loc) {
assert(CGF.CurFn && "No function in current CodeGenFunction.");
- llvm::Value *GTid = nullptr;
- OpenMPGtidMapTy::iterator I = OpenMPGtidMap.find(CGF.CurFn);
- if (I != OpenMPGtidMap.end()) {
- GTid = I->second;
+ llvm::Value *ThreadID = nullptr;
+ OpenMPThreadIDMapTy::iterator I = OpenMPThreadIDMap.find(CGF.CurFn);
+ if (I != OpenMPThreadIDMap.end()) {
+ ThreadID = I->second;
} else {
// Check if current function is a function which has first parameter
// with type int32 and name ".global_tid.".
@@ -145,24 +168,24 @@ llvm::Value *CGOpenMPRuntime::GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
CGF.CurFn->arg_begin()->getName() == ".global_tid.") {
CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
- GTid = CGF.Builder.CreateLoad(CGF.CurFn->arg_begin());
+ ThreadID = CGF.Builder.CreateLoad(CGF.CurFn->arg_begin());
} else {
// Generate "int32 .kmpc_global_thread_num.addr;"
CGBuilderTy::InsertPointGuard IPG(CGF.Builder);
CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt);
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc)};
- GTid = CGF.EmitRuntimeCall(
+ ThreadID = CGF.EmitRuntimeCall(
CreateRuntimeFunction(OMPRTL__kmpc_global_thread_num), Args);
}
- OpenMPGtidMap[CGF.CurFn] = GTid;
+ OpenMPThreadIDMap[CGF.CurFn] = ThreadID;
}
- return GTid;
+ return ThreadID;
}
void CGOpenMPRuntime::FunctionFinished(CodeGenFunction &CGF) {
assert(CGF.CurFn && "No function in current CodeGenFunction.");
- if (OpenMPGtidMap.count(CGF.CurFn))
- OpenMPGtidMap.erase(CGF.CurFn);
+ if (OpenMPThreadIDMap.count(CGF.CurFn))
+ OpenMPThreadIDMap.erase(CGF.CurFn);
if (OpenMPLocMap.count(CGF.CurFn))
OpenMPLocMap.erase(CGF.CurFn);
}
@@ -219,10 +242,33 @@ CGOpenMPRuntime::CreateRuntimeFunction(OpenMPRTLFunction Function) {
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_critical");
break;
}
+ case OMPRTL__kmpc_barrier: {
+ // Build void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier");
+ break;
+ }
}
return RTLFn;
}
+void CGOpenMPRuntime::EmitOMPParallelCall(CodeGenFunction &CGF,
+ SourceLocation Loc,
+ llvm::Value *OutlinedFn,
+ llvm::Value *CapturedStruct) {
+ // Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/)
+ llvm::Value *Args[] = {
+ EmitOpenMPUpdateLocation(CGF, Loc),
+ CGF.Builder.getInt32(1), // Number of arguments after 'microtask' argument
+ // (there is only one additional argument - 'context')
+ CGF.Builder.CreateBitCast(OutlinedFn, getKmpc_MicroPointerTy()),
+ CGF.EmitCastToVoidPtr(CapturedStruct)};
+ auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_fork_call);
+ CGF.EmitRuntimeCall(RTLFn, Args);
+}
+
llvm::Value *CGOpenMPRuntime::GetCriticalRegionLock(StringRef CriticalName) {
SmallString<256> Buffer;
llvm::raw_svector_ostream Out(Buffer);
@@ -245,7 +291,7 @@ void CGOpenMPRuntime::EmitOMPCriticalRegionStart(CodeGenFunction &CGF,
SourceLocation Loc) {
// Prepare other arguments and build a call to __kmpc_critical
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
- GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock};
+ GetOpenMPThreadID(CGF, Loc), RegionLock};
auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_critical);
CGF.EmitRuntimeCall(RTLFn, Args);
}
@@ -255,8 +301,19 @@ void CGOpenMPRuntime::EmitOMPCriticalRegionEnd(CodeGenFunction &CGF,
SourceLocation Loc) {
// Prepare other arguments and build a call to __kmpc_end_critical
llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc),
- GetOpenMPGlobalThreadNum(CGF, Loc), RegionLock};
+ GetOpenMPThreadID(CGF, Loc), RegionLock};
auto RTLFn =
CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_end_critical);
CGF.EmitRuntimeCall(RTLFn, Args);
}
+
+void CGOpenMPRuntime::EmitOMPBarrierCall(CodeGenFunction &CGF,
+ SourceLocation Loc,
+ OpenMPLocationFlags Flags) {
+ // Build call __kmpc_barrier(loc, thread_id)
+ llvm::Value *Args[] = {EmitOpenMPUpdateLocation(CGF, Loc, Flags),
+ GetOpenMPThreadID(CGF, Loc)};
+ auto RTLFn = CreateRuntimeFunction(CGOpenMPRuntime::OMPRTL__kmpc_barrier);
+ CGF.EmitRuntimeCall(RTLFn, Args);
+}
+
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h
index bba2c8c4d78..ec6115fb094 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.h
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.h
@@ -14,33 +14,49 @@
#ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H
#define LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIME_H
+#include "CodeGenFunction.h"
+#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
-namespace llvm {
-class AllocaInst;
-class CallInst;
-class GlobalVariable;
-class Constant;
-class Function;
-class Module;
-class StructLayout;
-class ArrayType;
-class FunctionType;
-class StructType;
-class Type;
-class Value;
-} // namespace llvm
-
namespace clang {
namespace CodeGen {
-class CodeGenFunction;
-class CodeGenModule;
+/// \brief API for captured statement code generation in OpenMP constructs.
+class CGOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo {
+public:
+ CGOpenMPRegionInfo(const OMPExecutableDirective &D, const CapturedStmt &S,
+ const VarDecl *ThreadIDVar)
+ : CGCapturedStmtInfo(S, CR_OpenMP), ThreadIDVar(ThreadIDVar),
+ Directive(D) {}
+
+ virtual ~CGOpenMPRegionInfo() override{};
+
+ /// \brief Gets a variable or parameter for storing global thread id
+ /// inside OpenMP construct.
+ const VarDecl *getThreadIDVariable() const { return ThreadIDVar; }
+
+ static bool classof(const CGCapturedStmtInfo *Info) {
+ return Info->getKind() == CR_OpenMP;
+ }
+
+ /// \brief Emit the captured statement body.
+ virtual void EmitBody(CodeGenFunction &CGF, Stmt *S) override;
+
+ /// \brief Get the name of the capture helper.
+ virtual StringRef getHelperName() const override { return ".omp_outlined."; }
+
+private:
+ /// \brief A variable or parameter storing global thread id for OpenMP
+ /// constructs.
+ const VarDecl *ThreadIDVar;
+ /// \brief OpenMP executable directive associated with the region.
+ const OMPExecutableDirective &Directive;
+};
class CGOpenMPRuntime {
public:
@@ -76,7 +92,9 @@ public:
OMPRTL__kmpc_critical,
// Call to void __kmpc_end_critical(ident_t *loc, kmp_int32 global_tid,
// kmp_critical_name *crit);
- OMPRTL__kmpc_end_critical
+ OMPRTL__kmpc_end_critical,
+ // Call to void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid);
+ OMPRTL__kmpc_barrier
};
private:
@@ -139,24 +157,15 @@ private:
/// \brief Map of local debug location and functions.
typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPLocMapTy;
OpenMPLocMapTy OpenMPLocMap;
- /// \brief Map of local gtid and functions.
- typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPGtidMapTy;
- OpenMPGtidMapTy OpenMPGtidMap;
+ /// \brief Map of local ThreadID and functions.
+ typedef llvm::DenseMap<llvm::Function *, llvm::Value *> OpenMPThreadIDMapTy;
+ OpenMPThreadIDMapTy OpenMPThreadIDMap;
/// \brief Type kmp_critical_name, originally defined as typedef kmp_int32
/// kmp_critical_name[8];
llvm::ArrayType *KmpCriticalNameTy;
/// \brief Map of critical regions names and the corresponding lock objects.
llvm::StringMap<llvm::Value *, llvm::BumpPtrAllocator> CriticalRegionVarNames;
-public:
- explicit CGOpenMPRuntime(CodeGenModule &CGM);
- virtual ~CGOpenMPRuntime() {}
-
- /// \brief Cleans up references to the objects in finished function.
- /// \param CGF Reference to finished CodeGenFunction.
- ///
- void FunctionFinished(CodeGenFunction &CGF);
-
/// \brief Emits object of ident_t type with info for source location.
/// \param CGF Reference to current CodeGenFunction.
/// \param Loc Clang source location.
@@ -166,13 +175,6 @@ public:
EmitOpenMPUpdateLocation(CodeGenFunction &CGF, SourceLocation Loc,
OpenMPLocationFlags Flags = OMP_IDENT_KMPC);
- /// \brief Generates global thread number value.
- /// \param CGF Reference to current CodeGenFunction.
- /// \param Loc Clang source location.
- ///
- llvm::Value *GetOpenMPGlobalThreadNum(CodeGenFunction &CGF,
- SourceLocation Loc);
-
/// \brief Returns pointer to ident_t type;
llvm::Type *getIdentTyPointerTy();
@@ -184,6 +186,33 @@ public:
/// \return Specified function.
llvm::Constant *CreateRuntimeFunction(OpenMPRTLFunction Function);
+ /// \brief Gets thread id value for the current thread.
+ /// \param CGF Reference to current CodeGenFunction.
+ /// \param Loc Clang source location.
+ ///
+ llvm::Value *GetOpenMPThreadID(CodeGenFunction &CGF, SourceLocation Loc);
+
+public:
+ explicit CGOpenMPRuntime(CodeGenModule &CGM);
+ virtual ~CGOpenMPRuntime() {}
+
+ /// \brief Cleans up references to the objects in finished function.
+ /// \param CGF Reference to finished CodeGenFunction.
+ ///
+ void FunctionFinished(CodeGenFunction &CGF);
+
+ /// \brief Emits code for parallel call of the \a OutlinedFn with variables
+ /// captured in a record which address is stored in \a CapturedStruct.
+ /// \param CGF Reference to current CodeGenFunction.
+ /// \param Loc Clang source location.
+ /// \param OutlinedFn Outlined function to be run in parallel threads.
+ /// \param CapturedStruct A pointer to the record with the references to
+ /// variables used in \a OutlinedFn function.
+ ///
+ virtual void EmitOMPParallelCall(CodeGenFunction &CGF, SourceLocation Loc,
+ llvm::Value *OutlinedFn,
+ llvm::Value *CapturedStruct);
+
/// \brief Returns corresponding lock object for the specified critical region
/// name. If the lock object does not exist it is created, otherwise the
/// reference to the existing copy is returned.
@@ -208,6 +237,14 @@ public:
virtual void EmitOMPCriticalRegionEnd(CodeGenFunction &CGF,
llvm::Value *RegionLock,
SourceLocation Loc);
+
+ /// \brief Emits a barrier for OpenMP threads.
+ /// \param CGF Reference to current CodeGenFunction.
+ /// \param Loc Clang source location.
+ /// \param Flags Flags for the barrier.
+ ///
+ virtual void EmitOMPBarrierCall(CodeGenFunction &CGF, SourceLocation Loc,
+ OpenMPLocationFlags Flags);
};
} // namespace CodeGen
} // namespace clang
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 985cc0e62ae..5efff2ccbde 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -24,6 +24,110 @@ using namespace CodeGen;
// OpenMP Directive Emission
//===----------------------------------------------------------------------===//
+void CodeGenFunction::EmitOMPAggregateAssign(LValue OriginalAddr,
+ llvm::Value *PrivateAddr,
+ const Expr *AssignExpr,
+ QualType OriginalType,
+ const VarDecl *VDInit) {
+ EmitBlock(createBasicBlock(".omp.assign.begin."));
+ if (!isa<CXXConstructExpr>(AssignExpr) || isTrivialInitializer(AssignExpr)) {
+ // Perform simple memcpy.
+ EmitAggregateAssign(PrivateAddr, OriginalAddr.getAddress(),
+ AssignExpr->getType());
+ } else {
+ // Perform element-by-element initialization.
+ QualType ElementTy;
+ auto SrcBegin = OriginalAddr.getAddress();
+ auto DestBegin = PrivateAddr;
+ auto ArrayTy = OriginalType->getAsArrayTypeUnsafe();
+ auto SrcNumElements = emitArrayLength(ArrayTy, ElementTy, SrcBegin);
+ auto DestNumElements = emitArrayLength(ArrayTy, ElementTy, DestBegin);
+ auto SrcEnd = Builder.CreateGEP(SrcBegin, SrcNumElements);
+ auto DestEnd = Builder.CreateGEP(DestBegin, DestNumElements);
+ // The basic structure here is a do-while loop, because we don't
+ // need to check for the zero-element case.
+ auto BodyBB = createBasicBlock("omp.arraycpy.body");
+ auto DoneBB = createBasicBlock("omp.arraycpy.done");
+ auto IsEmpty =
+ Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arraycpy.isempty");
+ Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB);
+
+ // Enter the loop body, making that address the current address.
+ auto EntryBB = Builder.GetInsertBlock();
+ EmitBlock(BodyBB);
+ auto SrcElementPast = Builder.CreatePHI(SrcBegin->getType(), 2,
+ "omp.arraycpy.srcElementPast");
+ SrcElementPast->addIncoming(SrcEnd, EntryBB);
+ auto DestElementPast = Builder.CreatePHI(DestBegin->getType(), 2,
+ "omp.arraycpy.destElementPast");
+ DestElementPast->addIncoming(DestEnd, EntryBB);
+
+ // Shift the address back by one element.
+ auto NegativeOne = llvm::ConstantInt::get(SizeTy, -1, true);
+ auto DestElement = Builder.CreateGEP(DestElementPast, NegativeOne,
+ "omp.arraycpy.dest.element");
+ auto SrcElement = Builder.CreateGEP(SrcElementPast, NegativeOne,
+ "omp.arraycpy.src.element");
+ {
+ // Create RunCleanScope to cleanup possible temps.
+ CodeGenFunction::RunCleanupsScope Init(*this);
+ // Emit initialization for single element.
+ LocalDeclMap[VDInit] = SrcElement;
+ EmitAnyExprToMem(AssignExpr, DestElement,
+ AssignExpr->getType().getQualifiers(),
+ /*IsInitializer*/ false);
+ LocalDeclMap.erase(VDInit);
+ }
+
+ // Check whether we've reached the end.
+ auto Done =
+ Builder.CreateICmpEQ(DestElement, DestBegin, "omp.arraycpy.done");
+ Builder.CreateCondBr(Done, DoneBB, BodyBB);
+ DestElementPast->addIncoming(DestElement, Builder.GetInsertBlock());
+ SrcElementPast->addIncoming(SrcElement, Builder.GetInsertBlock());
+
+ // Done.
+ EmitBlock(DoneBB, true);
+ }
+ EmitBlock(createBasicBlock(".omp.assign.end."));
+}
+
+void CodeGenFunction::EmitOMPFirstprivateClause(
+ const OMPExecutableDirective &D,
+ CodeGenFunction::OuterDeclMapTy &OuterDeclMap) {
+ auto PrivateFilter = [](const OMPClause *C) -> bool {
+ return C->getClauseKind() == OMPC_firstprivate;
+ };
+ for (OMPExecutableDirective::filtered_clause_iterator<decltype(PrivateFilter)>
+ I(D.clauses(), PrivateFilter); I; ++I) {
+ auto *C = cast<OMPFirstprivateClause>(*I);
+ auto IRef = C->varlist_begin();
+ auto InitsRef = C->inits().begin();
+ for (auto IInit : C->private_copies()) {
+ auto VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
+ if (*InitsRef != nullptr) {
+ // Emit VarDecl with copy init for arrays.
+ auto *FD = CapturedStmtInfo->lookup(
+ cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl()));
+ LValue Base = MakeNaturalAlignAddrLValue(
+ CapturedStmtInfo->getContextValue(),
+ getContext().getTagDeclType(FD->getParent()));
+ auto OriginalAddr = EmitLValueForField(Base, FD);
+ auto VDInit = cast<VarDecl>(cast<DeclRefExpr>(*InitsRef)->getDecl());
+ auto Emission = EmitAutoVarAlloca(*VD);
+ // Emit initialization of aggregate firstprivate vars.
+ EmitOMPAggregateAssign(OriginalAddr, Emission.getAllocatedAddress(),
+ VD->getInit(), (*IRef)->getType(), VDInit);
+ EmitAutoVarCleanups(Emission);
+ } else
+ // Emit VarDecl with copy init.
+ EmitDecl(*VD);
+ OuterDeclMap[cast<DeclRefExpr>(*IRef)->getDecl()] = GetAddrOfLocalVar(VD);
+ ++IRef, ++InitsRef;
+ }
+ }
+}
+
void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
const CapturedStmt *CS = cast<CapturedStmt>(S.getAssociatedStmt());
llvm::Value *CapturedStruct = GenerateCapturedStmtArgument(*CS);
@@ -31,22 +135,13 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
llvm::Value *OutlinedFn;
{
CodeGenFunction CGF(CGM, true);
- CGCapturedStmtInfo CGInfo(*CS, CS->getCapturedRegionKind());
+ CGOpenMPRegionInfo CGInfo(S, *CS, *CS->getCapturedDecl()->param_begin());
CGF.CapturedStmtInfo = &CGInfo;
OutlinedFn = CGF.GenerateCapturedStmtFunction(*CS);
}
- // Build call __kmpc_fork_call(loc, 1, microtask, captured_struct/*context*/)
- llvm::Value *Args[] = {
- CGM.getOpenMPRuntime().EmitOpenMPUpdateLocation(*this, S.getLocStart()),
- Builder.getInt32(1), // Number of arguments after 'microtask' argument
- // (there is only one additional argument - 'context')
- Builder.CreateBitCast(OutlinedFn,
- CGM.getOpenMPRuntime().getKmpc_MicroPointerTy()),
- EmitCastToVoidPtr(CapturedStruct)};
- llvm::Constant *RTLFn = CGM.getOpenMPRuntime().CreateRuntimeFunction(
- CGOpenMPRuntime::OMPRTL__kmpc_fork_call);
- EmitRuntimeCall(RTLFn, Args);
+ CGM.getOpenMPRuntime().EmitOMPParallelCall(*this, S.getLocStart(), OutlinedFn,
+ CapturedStruct);
}
void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &S,
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index a4b231ddf4b..e471f157381 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/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.
@@ -1826,6 +1827,10 @@ public:
typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D,
llvm::Value *Address);
+ /// \brief Determine whether the given initializer is trivial in the sense
+ /// that it requires no code to be generated.
+ bool isTrivialInitializer(const Expr *Init);
+
/// EmitAutoVarDecl - Emit an auto variable declaration.
///
/// This function can be called with a null (unreachable) insert point.
@@ -1991,8 +1996,16 @@ public:
ArrayRef<const Attr *> Attrs = None);
llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K);
+ void GenerateCapturedStmtFunctionProlog(const CapturedStmt &S);
+ llvm::Function *GenerateCapturedStmtFunctionEpilog(const CapturedStmt &S);
llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S);
llvm::Value *GenerateCapturedStmtArgument(const CapturedStmt &S);
+ typedef llvm::DenseMap<const Decl *, llvm::Value *> OuterDeclMapTy;
+ void EmitOMPAggregateAssign(LValue OriginalAddr, llvm::Value *PrivateAddr,
+ const Expr *AssignExpr, QualType Type,
+ const VarDecl *VDInit);
+ void EmitOMPFirstprivateClause(const OMPExecutableDirective &D,
+ OuterDeclMapTy &OuterDeclMap);
void EmitOMPParallelDirective(const OMPParallelDirective &S);
void EmitOMPSimdDirective(const OMPSimdDirective &S);
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index ff2b2826092..159f1bb08ed 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3902,11 +3902,36 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
}
+namespace {
+class DiagsUninitializedSeveretyRAII {
+private:
+ DiagnosticsEngine &Diags;
+ SourceLocation SavedLoc;
+ bool IsIgnored;
+
+public:
+ DiagsUninitializedSeveretyRAII(DiagnosticsEngine &Diags, SourceLocation Loc,
+ bool IsIgnored)
+ : Diags(Diags), SavedLoc(Loc), IsIgnored(IsIgnored) {
+ if (!IsIgnored) {
+ Diags.setSeverity(/*Diag*/ diag::warn_uninit_self_reference_in_init,
+ /*Map*/ diag::Severity::Ignored, Loc);
+ }
+ }
+ ~DiagsUninitializedSeveretyRAII() {
+ if (!IsIgnored)
+ Diags.popMappings(SavedLoc);
+ }
+};
+}
+
OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
+ SmallVector<Expr *, 8> PrivateCopies;
+ SmallVector<Expr *, 8> Inits;
bool IsImplicitClause =
StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid();
auto ImplicitClauseLoc = DSAStack->getConstructLoc();
@@ -3916,11 +3941,13 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
+ PrivateCopies.push_back(nullptr);
+ Inits.push_back(nullptr);
continue;
}
- SourceLocation ELoc = IsImplicitClause ? ImplicitClauseLoc
- : RefExpr->getExprLoc();
+ SourceLocation ELoc =
+ IsImplicitClause ? ImplicitClauseLoc : RefExpr->getExprLoc();
// OpenMP [2.1, C/C++]
// A list item is a variable name.
// OpenMP [2.9.3.3, Restrictions, p.1]
@@ -3938,6 +3965,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
// It will be analyzed later.
Vars.push_back(DE);
+ PrivateCopies.push_back(nullptr);
+ Inits.push_back(nullptr);
continue;
}
@@ -3971,65 +4000,6 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// clause requires an accessible, unambiguous copy constructor for the
// class type.
Type = Context.getBaseElementType(Type);
- CXXRecordDecl *RD = getLangOpts().CPlusPlus
- ? Type.getNonReferenceType()->getAsCXXRecordDecl()
- : nullptr;
- // FIXME This code must be replaced by actual constructing/destructing of
- // the firstprivate variable.
- if (RD) {
- CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0);
- PartialDiagnostic PD =
- PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
- if (!CD ||
- CheckConstructorAccess(ELoc, CD,
- InitializedEntity::InitializeTemporary(Type),
- CD->getAccess(), PD) == AR_inaccessible ||
- CD->isDeleted()) {
- if (IsImplicitClause) {
- Diag(ImplicitClauseLoc,
- diag::err_omp_task_predetermined_firstprivate_required_method)
- << 0;
- Diag(RefExpr->getExprLoc(), diag::note_used_here);
- } else {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_firstprivate) << 1;
- }
- 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()) {
- if (IsImplicitClause) {
- Diag(ImplicitClauseLoc,
- diag::err_omp_task_predetermined_firstprivate_required_method)
- << 1;
- Diag(RefExpr->getExprLoc(), diag::note_used_here);
- } else {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_firstprivate) << 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);
- }
- }
// If an implicit firstprivate variable found it was checked already.
if (!IsImplicitClause) {
@@ -4119,15 +4089,67 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
}
}
+ Type = Type.getUnqualifiedType();
+ auto VDPrivate = VarDecl::Create(Context, CurContext, DE->getLocStart(),
+ ELoc, VD->getIdentifier(), VD->getType(),
+ VD->getTypeSourceInfo(), /*S*/ SC_Auto);
+ // Generate helper private variable and initialize it with the value of the
+ // original variable. The address of the original variable is replaced by
+ // the address of the new private variable in the CodeGen. This new variable
+ // is not added to IdResolver, so the code in the OpenMP region uses
+ // original variable for proper diagnostics and variable capturing.
+ Expr *VDInitRefExpr = nullptr;
+ // For arrays generate initializer for single element and replace it by the
+ // original array element in CodeGen.
+ if (DE->getType()->isArrayType()) {
+ auto VDInit = VarDecl::Create(Context, CurContext, DE->getLocStart(),
+ ELoc, VD->getIdentifier(), Type,
+ VD->getTypeSourceInfo(), /*S*/ SC_Auto);
+ CurContext->addHiddenDecl(VDInit);
+ VDInitRefExpr = DeclRefExpr::Create(
+ Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
+ /*TemplateKWLoc*/ SourceLocation(), VDInit,
+ /*isEnclosingLocal*/ false, ELoc, Type,
+ /*VK*/ VK_LValue);
+ VDInit->setIsUsed();
+ auto Init = DefaultLvalueConversion(VDInitRefExpr).get();
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(VDInit);
+ InitializationKind Kind = InitializationKind::CreateCopy(ELoc, ELoc);
+
+ InitializationSequence InitSeq(*this, Entity, Kind, Init);
+ ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Init);
+ if (Result.isInvalid())
+ VDPrivate->setInvalidDecl();
+ else
+ VDPrivate->setInit(Result.getAs<Expr>());
+ } else {
+ AddInitializerToDecl(VDPrivate, DefaultLvalueConversion(DE).get(),
+ /*DirectInit*/ false, /*TypeMayContainAuto*/ false);
+ }
+ if (VDPrivate->isInvalidDecl()) {
+ if (IsImplicitClause) {
+ Diag(DE->getExprLoc(),
+ diag::note_omp_task_predetermined_firstprivate_here);
+ }
+ continue;
+ }
+ CurContext->addDecl(VDPrivate);
+ auto VDPrivateRefExpr = DeclRefExpr::Create(
+ Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
+ /*TemplateKWLoc*/ SourceLocation(), VDPrivate,
+ /*isEnclosingLocal*/ false, DE->getLocStart(), DE->getType(),
+ /*VK*/ VK_LValue);
DSAStack->addDSA(VD, DE, OMPC_firstprivate);
Vars.push_back(DE);
+ PrivateCopies.push_back(VDPrivateRefExpr);
+ Inits.push_back(VDInitRefExpr);
}
if (Vars.empty())
return nullptr;
return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
- Vars);
+ Vars, PrivateCopies, Inits);
}
OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index c8343373ad6..0b8efb51401 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1854,6 +1854,14 @@ void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *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);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setInits(Vars);
}
void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 80d42b8ae5f..a963d6b875a 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1761,8 +1761,15 @@ void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *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);
+ }
+ for (auto *VE : C->inits()) {
+ Writer->Writer.AddStmt(VE);
+ }
}
void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) {
OpenPOWER on IntegriCloud