76 changes: 72 additions & 4 deletions clang/lib/CodeGen/CGOpenMPRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,23 @@

#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/IR/ValueHandle.h"

namespace llvm {
class ArrayType;
class Constant;
class Function;
class FunctionType;
class GlobalVariable;
class StructType;
class Type;
class Value;
} // namespace llvm

namespace clang {
class VarDecl;

class OMPExecutableDirective;
class VarDecl;
Expand Down Expand Up @@ -62,9 +66,15 @@ class CGOpenMPRuntime {
OMP_IDENT_BARRIER_IMPL_SINGLE = 0x140
};
enum OpenMPRTLFunction {
// Call to void __kmpc_fork_call(ident_t *loc, kmp_int32 argc, kmpc_micro
// microtask, ...);
/// \brief Call to void __kmpc_fork_call(ident_t *loc, kmp_int32 argc,
/// kmpc_micro microtask, ...);
OMPRTL__kmpc_fork_call,
/// \brief Call to void *__kmpc_threadprivate_cached(ident_t *loc,
/// kmp_int32 global_tid, void *data, size_t size, void ***cache);
OMPRTL__kmpc_threadprivate_cached,
/// \brief Call to void __kmpc_threadprivate_register( ident_t *,
/// void *data, kmpc_ctor ctor, kmpc_cctor cctor, kmpc_dtor dtor);
OMPRTL__kmpc_threadprivate_register,
// Call to __kmpc_int32 kmpc_global_thread_num(ident_t *loc);
OMPRTL__kmpc_global_thread_num,
// Call to void __kmpc_critical(ident_t *loc, kmp_int32 global_tid,
Expand Down Expand Up @@ -155,8 +165,13 @@ class CGOpenMPRuntime {
/// \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;
/// \brief An ordered map of auto-generated variables to their unique names.
/// It stores variables with the following names: 1) ".gomp_critical_user_" +
/// <critical_section_name> + ".var" for "omp critical" directives; 2)
/// <mangled_name_for_global_var> + ".cache." for cache for threadprivate
/// variables.
llvm::StringMap<llvm::AssertingVH<llvm::Constant>, llvm::BumpPtrAllocator>
InternalVars;

/// \brief Emits object of ident_t type with info for source location.
/// \param Flags Flags for OpenMP location.
Expand All @@ -176,6 +191,13 @@ class CGOpenMPRuntime {
/// \return Specified function.
llvm::Constant *CreateRuntimeFunction(OpenMPRTLFunction Function);

/// \brief If the specified mangled name is not in the module, create and
/// return threadprivate cache object. This object is a pointer's worth of
/// storage that's reserved for use by the OpenMP runtime.
/// \param D Threadprivate variable.
/// \return Cache variable for the specified threadprivate.
llvm::Constant *getOrCreateThreadPrivateCache(const VarDecl *VD);

/// \brief Emits address of the word in a memory where current thread id is
/// stored.
virtual llvm::Value *EmitThreadIDAddress(CodeGenFunction &CGF,
Expand All @@ -185,6 +207,28 @@ class CGOpenMPRuntime {
///
llvm::Value *GetOpenMPThreadID(CodeGenFunction &CGF, SourceLocation Loc);

/// \brief Gets (if variable with the given name already exist) or creates
/// internal global variable with the specified Name. The created variable has
/// linkage CommonLinkage by default and is initialized by null value.
/// \param Ty Type of the global variable. If it is exist already the type
/// must be the same.
/// \param Name Name of the variable.
llvm::Constant *GetOrCreateInternalVariable(llvm::Type *Ty,
const llvm::Twine &Name);

/// \brief Set of threadprivate variables with the generated initializer.
llvm::DenseSet<const VarDecl *> ThreadPrivateWithDefinition;

/// \brief Emits initialization code for the threadprivate variables.
/// \param VDAddr Address of the global variable \a VD.
/// \param Ctor Pointer to a global init function for \a VD.
/// \param CopyCtor Pointer to a global copy function for \a VD.
/// \param Dtor Pointer to a global destructor function for \a VD.
/// \param Loc Location of threadprivate declaration.
void EmitOMPThreadPrivateVarInit(CodeGenFunction &CGF, llvm::Value *VDAddr,
llvm::Value *Ctor, llvm::Value *CopyCtor,
llvm::Value *Dtor, SourceLocation Loc);

public:
explicit CGOpenMPRuntime(CodeGenModule &CGM);
virtual ~CGOpenMPRuntime() {}
Expand Down Expand Up @@ -261,6 +305,30 @@ class CGOpenMPRuntime {
virtual void EmitOMPNumThreadsClause(CodeGenFunction &CGF,
llvm::Value *NumThreads,
SourceLocation Loc);

/// \brief Returns address of the threadprivate variable for the current
/// thread.
/// \param D Threadprivate variable.
/// \param VDAddr Address of the global variable \a VD.
/// \param Loc Location of the reference to threadprivate var.
/// \return Address of the threadprivate variable for the current thread.
virtual llvm::Value *getOMPAddrOfThreadPrivate(CodeGenFunction &CGF,
const VarDecl *VD,
llvm::Value *VDAddr,
SourceLocation Loc);

/// \brief Emit a code for initialization of threadprivate variable. It emits
/// a call to runtime library which adds initial value to the newly created
/// threadprivate variable (if it is not constant) and registers destructor
/// for the variable (if any).
/// \param VD Threadprivate variable.
/// \param VDAddr Address of the global variable \a VD.
/// \param Loc Location of threadprivate declaration.
/// \param PerformInit true if initialization expression is not constant.
virtual llvm::Function *
EmitOMPThreadPrivateVarDefinition(const VarDecl *VD, llvm::Value *VDAddr,
SourceLocation Loc, bool PerformInit,
CodeGenFunction *CGF = nullptr);
};
} // namespace CodeGen
} // namespace clang
Expand Down
19 changes: 19 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3230,6 +3230,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
}

case Decl::OMPThreadPrivate:
EmitOMPThreadPrivateDecl(cast<OMPThreadPrivateDecl>(D));
break;

case Decl::ClassTemplateSpecialization: {
const auto *Spec = cast<ClassTemplateSpecializationDecl>(D);
if (DebugInfo &&
Expand Down Expand Up @@ -3506,3 +3510,18 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
return getCXXABI().getAddrOfRTTIDescriptor(Ty);
}

void CodeGenModule::EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) {
for (auto RefExpr : D->varlists()) {
auto *VD = cast<VarDecl>(cast<DeclRefExpr>(RefExpr)->getDecl());
bool PerformInit =
VD->getAnyInitializer() &&
!VD->getAnyInitializer()->isConstantInitializer(getContext(),
/*ForRef=*/false);
if (auto InitFunction =
getOpenMPRuntime().EmitOMPThreadPrivateVarDefinition(
VD, GetAddrOfGlobalVar(VD), RefExpr->getLocStart(),
PerformInit))
CXXGlobalInits.push_back(InitFunction);
}
}

5 changes: 5 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1087,6 +1087,11 @@ class CodeGenModule : public CodeGenTypeCache {
void setAliasAttributes(const Decl *D, llvm::GlobalValue *GV);

void addReplacement(StringRef Name, llvm::Constant *C);

/// \brief Emit a code for threadprivate directive.
/// \param D Threadprivate declaration.
void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D);

private:
llvm::Constant *
GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D,
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Frontend/MultiplexConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class MultiplexASTMutationListener : public ASTMutationListener {
const ObjCPropertyDecl *OrigProp,
const ObjCCategoryDecl *ClassExt) override;
void DeclarationMarkedUsed(const Decl *D) override;
void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override;

private:
std::vector<ASTMutationListener*> Listeners;
Expand Down Expand Up @@ -180,6 +181,11 @@ void MultiplexASTMutationListener::DeclarationMarkedUsed(const Decl *D) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->DeclarationMarkedUsed(D);
}
void MultiplexASTMutationListener::DeclarationMarkedOpenMPThreadPrivate(
const Decl *D) {
for (size_t i = 0, e = Listeners.size(); i != e; ++i)
Listeners[i]->DeclarationMarkedOpenMPThreadPrivate(D);
}

} // end namespace clang

Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
HandlePragmaOpenCLExtension();
return DeclGroupPtrTy();
case tok::annot_pragma_openmp:
ParseOpenMPDeclarativeDirective();
return DeclGroupPtrTy();
return ParseOpenMPDeclarativeDirective();
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
return DeclGroupPtrTy();
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//

#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclOpenMP.h"
Expand Down Expand Up @@ -847,6 +848,10 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) {

Vars.push_back(RefExpr);
DSAStack->addDSA(VD, DE, OMPC_threadprivate);
VD->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(
Context, SourceRange(Loc, Loc)));
if (auto *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPThreadPrivate(VD);
}
OMPThreadPrivateDecl *D = nullptr;
if (!Vars.empty()) {
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Serialization/ASTCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ enum DeclUpdateKind {
UPD_CXX_DEDUCED_RETURN_TYPE,
UPD_DECL_MARKED_USED,
UPD_MANGLING_NUMBER,
UPD_STATIC_LOCAL_NUMBER
UPD_STATIC_LOCAL_NUMBER,
UPD_DECL_MARKED_OPENMP_THREADPRIVATE
};

TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT);
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2274,7 +2274,8 @@ static bool isConsumerInterestedIn(Decl *D, bool HasBody) {
if (isa<FileScopeAsmDecl>(D) ||
isa<ObjCProtocolDecl>(D) ||
isa<ObjCImplDecl>(D) ||
isa<ImportDecl>(D))
isa<ImportDecl>(D) ||
isa<OMPThreadPrivateDecl>(D))
return true;
if (VarDecl *Var = dyn_cast<VarDecl>(D))
return Var->isFileVarDecl() &&
Expand Down Expand Up @@ -3686,6 +3687,10 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
case UPD_STATIC_LOCAL_NUMBER:
Reader.Context.setStaticLocalNumber(cast<VarDecl>(D), Record[Idx++]);
break;
case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit(
Reader.Context, ReadSourceRange(Record, Idx)));
break;
}
}
}
12 changes: 12 additions & 0 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4788,6 +4788,10 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
case UPD_STATIC_LOCAL_NUMBER:
Record.push_back(Update.getNumber());
break;
case UPD_DECL_MARKED_OPENMP_THREADPRIVATE:
AddSourceRange(D->getAttr<OMPThreadPrivateDeclAttr>()->getRange(),
Record);
break;
}
}

Expand Down Expand Up @@ -5881,3 +5885,11 @@ void ASTWriter::DeclarationMarkedUsed(const Decl *D) {

DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_USED));
}

void ASTWriter::DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {
assert(!WritingAST && "Already writing the AST!");
if (!D->isFromASTFile())
return;

DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE));
}
707 changes: 707 additions & 0 deletions clang/test/OpenMP/threadprivate_codegen.cpp

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions clang/test/PCH/chain-openmp-threadprivate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// no PCH
// RUN: %clang_cc1 -fopenmp=libiomp5 -emit-llvm -include %s -include %s %s -o - | FileCheck %s
// with PCH
// RUN: %clang_cc1 -fopenmp=libiomp5 -emit-llvm -chain-include %s -chain-include %s %s -o - | FileCheck %s
#if !defined(PASS1)
#define PASS1

extern "C" int* malloc (int size);
int *a = malloc(20);

#elif !defined(PASS2)
#define PASS2

#pragma omp threadprivate(a)

#else

// CHECK: call {{.*}} @__kmpc_threadprivate_register(

// CHECK-LABEL: foo
int foo() {
return *a;
// CHECK: call {{.*}} @__kmpc_global_thread_num(
// CHECK: call {{.*}} @__kmpc_threadprivate_cached(
}
#endif