Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -7895,7 +7895,9 @@ // We never need to emit an uninstantiated function template. if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) return false; - } else + } else if (isa(D)) + return true; + else return false; // If this is a member of a class template, we do not need to emit it. Index: lib/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp +++ lib/CodeGen/CGDecl.cpp @@ -19,6 +19,7 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" @@ -86,11 +87,12 @@ case Decl::StaticAssert: // static_assert(X, ""); [C++0x] case Decl::Label: // __label__ x; case Decl::Import: - case Decl::OMPThreadPrivate: case Decl::Empty: // None of these decls require codegen support. return; - + case Decl::OMPThreadPrivate: + CGM.EmitOMPThreadPrivateDecl(cast(&D)); + return; case Decl::NamespaceAlias: if (CGDebugInfo *DI = getDebugInfo()) DI->EmitNamespaceAlias(cast(D)); Index: lib/CodeGen/CGDeclCXX.cpp =================================================================== --- lib/CodeGen/CGDeclCXX.cpp +++ lib/CodeGen/CGDeclCXX.cpp @@ -14,8 +14,10 @@ #include "CodeGenFunction.h" #include "CGCXXABI.h" #include "CGObjCRuntime.h" +#include "CGOpenMPRuntime.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/IR/CallSite.h" #include "llvm/IR/Intrinsics.h" #include "llvm/Support/Path.h" @@ -541,3 +543,96 @@ return fn; } + +void CodeGenModule::EmitCXXOMPThreadPrivateInitFunction(const VarDecl &VD, + llvm::Constant *Addr, + bool PerformInit, + bool PerformDestroy) { + QualType ASTTy = VD.getType(); + + llvm::Value *Ctor = nullptr, *CCtor = nullptr, *Dtor = nullptr; + if (PerformInit) { + CodeGenFunction CtorCGF(*this); + FunctionArgList Args; + ImplicitParamDecl Dst(Context, /*DC*/ nullptr, SourceLocation(), + /*Id*/ nullptr, getContext().VoidPtrTy); + Args.push_back(&Dst); + + const CGFunctionInfo &FI = getTypes().arrangeFreeFunctionDeclaration( + getContext().VoidPtrTy, Args, FunctionType::ExtInfo(), + /*isVariadic*/ false); + auto FTy = getTypes().GetFunctionType(FI); + auto Fn = + CreateGlobalInitOrDestructFunction(*this, FTy, ".__kmpc_global_ctor_."); + CtorCGF.StartFunction(GlobalDecl(), getContext().VoidPtrTy, Fn, FI, Args, + SourceLocation()); + auto Arg = + CtorCGF.EmitScalarConversion(Fn->arg_begin(), getContext().VoidPtrTy, + getContext().getPointerType(ASTTy)); + CtorCGF.EmitAnyExprToMem(VD.getAnyInitializer(), Arg, + VD.getAnyInitializer()->getType().getQualifiers(), + /*IsInitializer*/ true); + CtorCGF.Builder.CreateStore(Fn->arg_begin(), CtorCGF.ReturnValue); + CtorCGF.FinishFunction(); + Ctor = Fn; + } + if (PerformDestroy) { + CodeGenFunction DtorCGF(*this); + FunctionArgList Args; + ImplicitParamDecl Dst(Context, /*DC*/ nullptr, SourceLocation(), + /*Id*/ nullptr, getContext().VoidPtrTy); + Args.push_back(&Dst); + + const CGFunctionInfo &FI = getTypes().arrangeFreeFunctionDeclaration( + getContext().VoidTy, Args, FunctionType::ExtInfo(), false); + auto FTy = getTypes().GetFunctionType(FI); + auto Fn = + CreateGlobalInitOrDestructFunction(*this, FTy, ".__kmpc_global_dtor_."); + DtorCGF.StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FI, Args, + SourceLocation()); + DtorCGF.emitDestroy(Fn->arg_begin(), ASTTy, + DtorCGF.getDestroyer(ASTTy.isDestructedType()), + DtorCGF.needsEHCleanup(ASTTy.isDestructedType())); + DtorCGF.FinishFunction(); + Dtor = Fn; + } + auto CCtorTy = llvm::FunctionType::get(VoidPtrTy, { VoidPtrTy, VoidPtrTy }, + /*isVarArg*/ false)->getPointerTo(); + CCtor = llvm::Constant::getNullValue(CCtorTy); + if (Ctor == nullptr) { + auto CtorTy = llvm::FunctionType::get(VoidPtrTy, { VoidPtrTy }, + /*isVarArg*/ false)->getPointerTo(); + Ctor = llvm::Constant::getNullValue(CtorTy); + } + if (Dtor == nullptr) { + auto DtorTy = llvm::FunctionType::get(VoidTy, { VoidPtrTy }, + /*isVarArg*/ false)->getPointerTo(); + Dtor = llvm::Constant::getNullValue(DtorTy); + } + auto InitFunctionTy = llvm::FunctionType::get(VoidTy, /*isVarArg*/ false); + auto InitFunction = CreateGlobalInitOrDestructFunction( + *this, InitFunctionTy, ".__omp_threadprivate_init_."); + CodeGenFunction InitCGF(*this); + FunctionArgList ArgList; + InitCGF.StartFunction(GlobalDecl(), getContext().VoidTy, InitFunction, + getTypes().arrangeNullaryFunction(), ArgList, + SourceLocation()); + // Call kmp_int32 __kmpc_global_thread_num(&loc) to init OpenMP runtime + // library. + InitCGF.EmitRuntimeCall( + OpenMPRuntime->CreateRuntimeFunction( + CGOpenMPRuntime::OMPRTL__kmpc_global_thread_num), + { OpenMPRuntime->EmitOpenMPUpdateLocation(InitCGF, VD.getLocation()) }); + // Call __kmpc_threadprivate_register(&loc, &var, ctor, cctor/*NULL*/, dtor) + // to register constructor/destructor for variable. + InitCGF.EmitRuntimeCall( + OpenMPRuntime->CreateRuntimeFunction( + CGOpenMPRuntime::OMPRTL__kmpc_threadprivate_register), + { OpenMPRuntime->EmitOpenMPUpdateLocation(InitCGF, VD.getLocation()), + InitCGF.Builder.CreatePointerCast(Addr, VoidPtrTy), + Ctor, + CCtor, + Dtor }); + InitCGF.FinishFunction(); + CXXGlobalInits.push_back(InitFunction); +} Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -16,6 +16,7 @@ #include "CGCall.h" #include "CGDebugInfo.h" #include "CGObjCRuntime.h" +#include "CGOpenMPRuntime.h" #include "CGRecordLayout.h" #include "CodeGenModule.h" #include "TargetInfo.h" @@ -1718,6 +1719,14 @@ return CGF.Builder.CreateBitCast(V, IRType->getPointerTo(AS), Name); } +static LValue EmitThreadPrivateVarDeclLValue( + CodeGenFunction &CGF, const VarDecl *VD, QualType T, llvm::Value *V, + llvm::Type *RealVarTy, CharUnits Alignment, SourceLocation Loc) { + V = CGF.CGM.getOpenMPRuntime().getAddrOfThreadPrivate(CGF, V, VD, Loc); + V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy); + return CGF.MakeAddrLValue(V, T, Alignment); +} + static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF, const Expr *E, const VarDecl *VD) { QualType T = E->getType(); @@ -1731,6 +1740,11 @@ V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy); CharUnits Alignment = CGF.getContext().getDeclAlign(VD); LValue LV; + if (CGF.getLangOpts().OpenMP && + CGF.CGM.getOpenMPRuntime().isThreadPrivateDecl(VD)) { + return EmitThreadPrivateVarDeclLValue(CGF, VD, T, V, RealVarTy, Alignment, + E->getExprLoc()); + } if (VD->getType()->isReferenceType()) { llvm::LoadInst *LI = CGF.Builder.CreateLoad(V); LI->setAlignment(Alignment.getQuantity()); @@ -1843,6 +1857,13 @@ if (!V && VD->isStaticLocal()) V = CGM.getStaticLocalDeclAddress(VD); + // Check if variable is threadprivate. + if (V && getLangOpts().OpenMP && + CGM.getOpenMPRuntime().isThreadPrivateDecl(VD)) + return EmitThreadPrivateVarDeclLValue( + *this, VD, T, V, getTypes().ConvertTypeForMem(VD->getType()), + Alignment, E->getExprLoc()); + // Use special handling for lambdas. if (!V) { if (FieldDecl *FD = LambdaCaptureFields.lookup(VD)) { Index: lib/CodeGen/CGOpenMPRuntime.h =================================================================== --- lib/CodeGen/CGOpenMPRuntime.h +++ lib/CodeGen/CGOpenMPRuntime.h @@ -16,6 +16,8 @@ #include "clang/AST/Type.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringMap.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" @@ -34,9 +36,9 @@ } namespace clang { +class VarDecl; namespace CodeGen { - class CodeGenFunction; class CodeGenModule; @@ -64,11 +66,17 @@ 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, - // Call to kmp_int32 kmpc_global_thread_num(ident_t *loc); - OMPRTL__kmpc_global_thread_num + /// \brief Call to kmp_int32 __kmpc_global_thread_num(ident_t *loc); + OMPRTL__kmpc_global_thread_num, + /// \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 }; private: @@ -134,6 +142,20 @@ /// \brief Map of local gtid and functions. typedef llvm::DenseMap OpenMPGtidMapTy; OpenMPGtidMapTy OpenMPGtidMap; + /// \brief Set of declarations marked as threadprivate. + typedef llvm::SmallPtrSet OpenMPThreadPrivateVarsTy; + OpenMPThreadPrivateVarsTy OpenMPThreadPrivateVars; + /// \brief Map of threadprivate vars and corresponding cache storages. + typedef llvm::StringMap OpenMPThreadPrivateMapTy; + OpenMPThreadPrivateMapTy OpenMPThreadPrivateMap; + + /// \brief If the specified mangled name is not in the module, create and + /// return threadprivate cache object. + /// \param D Threadprivate variable. + /// \param Addr Original global variable. + /// \return Cache variable for the specified threadprivate. + llvm::Constant *getOrCreateThreadPrivateCache(const VarDecl *VD, + llvm::Value *Addr); public: CGOpenMPRuntime(CodeGenModule &CGM); @@ -170,6 +192,27 @@ /// \param Function OpenMP runtime function. /// \return Specified function. llvm::Constant *CreateRuntimeFunction(OpenMPRTLFunction Function); + + /// \brief Registers variable as threadprivate. + /// \param D ThreadpVariable declration to be checked. + void addThreadPrivateDecl(const VarDecl *VD); + + /// \brief Checks if the specified declaration or any redeclarations are + /// marked as threadprivate. + /// \param D Variable declration to be checked. + /// \return true if any redeclrations of the specified declaration are marked + /// as threadprivate. + bool isThreadPrivateDecl(const VarDecl *VD) const; + + /// \brief Returns address of the threadprivate variable for the current + /// thread. + /// \param CGF Reference to current CodeGenFunction. + /// \param Addr Address of the original variable. + /// \param D Threadprivate variable. + /// \param Loc Location of the reference to threadprivate var. + /// \return Address of the threadprivate variable for the current thread. + llvm::Value *getAddrOfThreadPrivate(CodeGenFunction &CGF, llvm::Value *Addr, + const VarDecl *VD, SourceLocation Loc); }; } } Index: lib/CodeGen/CGOpenMPRuntime.cpp =================================================================== --- lib/CodeGen/CGOpenMPRuntime.cpp +++ lib/CodeGen/CGOpenMPRuntime.cpp @@ -166,7 +166,7 @@ llvm::Type *TypeParams[] = { getIdentTyPointerTy(), CGM.Int32Ty, getKmpc_MicroPointerTy() }; llvm::FunctionType *FnTy = - llvm::FunctionType::get(CGM.VoidTy, TypeParams, true); + llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ true); RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_call"); break; } @@ -174,10 +174,89 @@ // Build kmp_int32 __kmpc_global_thread_num(ident_t *loc); llvm::Type *TypeParams[] = { getIdentTyPointerTy() }; llvm::FunctionType *FnTy = - llvm::FunctionType::get(CGM.Int32Ty, TypeParams, false); + llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false); RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_global_thread_num"); break; } + case OMPRTL__kmpc_threadprivate_cached: { + // Build void *__kmpc_threadprivate_cached(ident_t *loc, + // kmp_int32 global_tid, void *data, size_t size, void ***cache); + llvm::Type *TypeParams[] = { + getIdentTyPointerTy(), CGM.Int32Ty, + CGM.VoidPtrTy, CGM.SizeTy, + CGM.VoidPtrTy->getPointerTo()->getPointerTo() + }; + llvm::FunctionType *FnTy = + llvm::FunctionType::get(CGM.VoidPtrTy, TypeParams, /*isVarArg*/ false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_threadprivate_cached"); + break; + } + case OMPRTL__kmpc_threadprivate_register: { + // Build void __kmpc_threadprivate_register(ident_t *, void *data, + // kmpc_ctor ctor, kmpc_cctor cctor, kmpc_dtor dtor); + // typedef void *(*kmpc_ctor)(void *); + auto KmpcCtorTy = llvm::FunctionType::get( + CGM.VoidPtrTy, { CGM.VoidPtrTy }, /*isVarArg*/ false)->getPointerTo(); + // typedef void (*kmpc_dtor)(void *); + auto KmpcCCtorTy = + llvm::FunctionType::get(CGM.VoidPtrTy, { CGM.VoidPtrTy, CGM.VoidPtrTy }, + /*isVarArg*/ false)->getPointerTo(); + // typedef void *(*kmpc_cctor)(void *, void *); + auto KmpcDtorTy = llvm::FunctionType::get( + CGM.VoidTy, { CGM.VoidPtrTy }, /*isVarArg*/ false)->getPointerTo(); + auto FnTy = llvm::FunctionType::get( + CGM.VoidTy, { getIdentTyPointerTy(), CGM.VoidPtrTy, KmpcCtorTy, + KmpcCCtorTy, KmpcDtorTy }, + /*isVarArg*/ false); + RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_threadprivate_register"); + break; + } } return RTLFn; } + +void CGOpenMPRuntime::addThreadPrivateDecl(const VarDecl *VD) { + OpenMPThreadPrivateVars.insert(VD); +} + +bool CGOpenMPRuntime::isThreadPrivateDecl(const VarDecl *VD) const { + auto CurDecl = VD->getMostRecentDecl(); + while (CurDecl) { + if (OpenMPThreadPrivateVars.count(CurDecl) > 0) + return true; + CurDecl = CurDecl->getPreviousDecl(); + } + return false; +} + +llvm::Constant * +CGOpenMPRuntime::getOrCreateThreadPrivateCache(const VarDecl *VD, + llvm::Value *Addr) { + StringRef MangledName = CGM.getMangledName(VD); + // Lookup the entry, lazily creating it if necessary. + auto &Entry = OpenMPThreadPrivateMap[MangledName]; + if (Entry == nullptr) { + // Create cache memory for threadprivate variable void **Var.cache; + Entry = new llvm::GlobalVariable( + CGM.getModule(), CGM.Int8PtrPtrTy, /*IsConstant*/ false, + llvm::GlobalValue::CommonLinkage, + llvm::Constant::getNullValue(CGM.Int8PtrPtrTy), ".cache.", + dyn_cast(Addr)); + } + + return Entry; +} + +llvm::Value *CGOpenMPRuntime::getAddrOfThreadPrivate(CodeGenFunction &CGF, + llvm::Value *Addr, + const VarDecl *VD, + SourceLocation Loc) { + auto VarTy = Addr->getType()->getPointerElementType(); + return CGF.EmitRuntimeCall( + CreateRuntimeFunction(OMPRTL__kmpc_threadprivate_cached), + { EmitOpenMPUpdateLocation(CGF, Loc), + GetOpenMPGlobalThreadNum(CGF, Loc), + CGF.Builder.CreatePointerCast(Addr, CGM.Int8PtrTy), + CGM.getSize(CGM.GetTargetTypeStoreSize(VarTy)), + getOrCreateThreadPrivateCache(VD, Addr) }); +} Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -1020,7 +1020,26 @@ /// are emitted lazily. void EmitGlobal(GlobalDecl D); + /// \brief Emit a code for threadprivate directive. + /// \param D Threadprivate declaration. + void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D); + + /// \brief Emits the function which registers constructor/destructor for + /// the specified threadprivate variable. + /// \param VD A threadprivate variable. + /// \param Addr The address of the original variable. + /// \param PerformInit Need to create initialization function. + /// \param PerformDestroy Need to create destroy function. + void EmitCXXOMPThreadPrivateInitFunction(const VarDecl &VD, + llvm::Constant *Addr, + bool PerformInit, + bool PerformDestroy); + private: + /// \brief Emit a code for threadprivate variable. + /// \brief VD Threadprivate variable. + void EmitOMPThreadPrivateVarDecl(const VarDecl *VD); + llvm::GlobalValue *GetGlobalValue(StringRef Ref); llvm::Constant * Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -1386,8 +1386,12 @@ return EmitGlobalFunctionDefinition(GD, GV); } - if (const auto *VD = dyn_cast(D)) - return EmitGlobalVarDefinition(VD); + if (const auto *VD = dyn_cast(D)) { + EmitGlobalVarDefinition(VD); + if (getLangOpts().OpenMP && OpenMPRuntime->isThreadPrivateDecl(VD)) + EmitOMPThreadPrivateVarDecl(VD); + return; + } llvm_unreachable("Invalid argument to EmitGlobalDefinition()"); } @@ -3176,6 +3180,10 @@ break; } + case Decl::OMPThreadPrivate: + EmitOMPThreadPrivateDecl(cast(D)); + break; + case Decl::ClassTemplateSpecialization: { const auto *Spec = cast(D); if (DebugInfo && @@ -3332,3 +3340,27 @@ return llvm::ConstantStruct::getAnon(Fields); } + +void CodeGenModule::EmitOMPThreadPrivateVarDecl(const VarDecl *VD) { + if ((VD = VD->getDefinition(Context)) != nullptr) { + QualType ASTTy = VD->getType(); + CXXRecordDecl *RD = ASTTy->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + bool PerformInit = RD && VD->getAnyInitializer() != nullptr; + bool PerformDestroy = RD && !RD->hasTrivialDestructor(); + auto DeclPtr = VD->isStaticLocal() ? getStaticLocalDeclAddress(VD) + : GetAddrOfGlobalVar(VD); + + if (DeclPtr && (PerformInit || PerformDestroy)) { + EmitCXXOMPThreadPrivateInitFunction(*VD, DeclPtr, PerformInit, + PerformDestroy); + } + } +} + +void CodeGenModule::EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) { + for (auto RefExpr : D->varlists()) { + const VarDecl *VD = cast(cast(RefExpr)->getDecl()); + EmitOMPThreadPrivateVarDecl(VD); + OpenMPRuntime->addThreadPrivateDecl(VD); + } +} Index: lib/CodeGen/ModuleBuilder.cpp =================================================================== --- lib/CodeGen/ModuleBuilder.cpp +++ lib/CodeGen/ModuleBuilder.cpp @@ -16,6 +16,7 @@ #include "CodeGenModule.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/AST/Expr.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/TargetInfo.h" @@ -104,6 +105,13 @@ return; Builder->UpdateCompletedType(D); + // In C++, we may have member functions that need to be emitted at this + // point. + if (Ctx->getLangOpts().CPlusPlus && !D->isDependentContext()) { + for (auto *M : D->decls()) + if (isa(M)) + Builder->EmitTopLevelDecl(M); + } } void HandleTagDeclRequiredDefinition(const TagDecl *D) override { Index: lib/Parse/Parser.cpp =================================================================== --- lib/Parse/Parser.cpp +++ lib/Parse/Parser.cpp @@ -624,8 +624,7 @@ HandlePragmaOpenCLExtension(); return DeclGroupPtrTy(); case tok::annot_pragma_openmp: - ParseOpenMPDeclarativeDirective(); - return DeclGroupPtrTy(); + return ParseOpenMPDeclarativeDirective(); case tok::annot_pragma_ms_pointers_to_members: HandlePragmaMSPointersToMembers(); return DeclGroupPtrTy(); Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -2183,7 +2183,7 @@ if (isa(D) || isa(D) || isa(D) || - isa(D)) + isa(D) || isa(D)) return true; if (VarDecl *Var = dyn_cast(D)) return Var->isFileVarDecl() && Index: test/OpenMP/threadprivate_codegen.cpp =================================================================== --- test/OpenMP/threadprivate_codegen.cpp +++ test/OpenMP/threadprivate_codegen.cpp @@ -0,0 +1,558 @@ +// RUN: %clang_cc1 -verify -DBODY -fopenmp=libiomp5 -triple x86_64-unknown-unknown -x c++ -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -DBODY -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -g -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK-DEBUG %s +// expected-no-diagnostics +#ifndef HEADER +#define HEADER +// CHECK-DAG: [[IDENT:%.+]] = type { i32, i32, i32, i32, i8* } +// CHECK-DAG: [[S1:%.+]] = type { [[INT:i[0-9]+]] } +// CHECK-DAG: [[S2:%.+]] = type { [[INT]], double } +// CHECK-DAG: [[S3:%.+]] = type { [[INT]], float } +// CHECK-DAG: [[S4:%.+]] = type { [[INT]], [[INT]] } +// CHECK-DAG: [[S5:%.+]] = type { [[INT]], [[INT]], [[INT]] } +// CHECK-DAG: [[SMAIN:%.+]] = type { [[INT]], double, double } +// CHECK-DEBUG-DAG: [[IDENT:%.+]] = type { i32, i32, i32, i32, i8* } +// CHECK-DEBUG-DAG: [[S1:%.+]] = type { [[INT:i[0-9]+]] } +// CHECK-DEBUG-DAG: [[S2:%.+]] = type { [[INT]], double } +// CHECK-DEBUG-DAG: [[S3:%.+]] = type { [[INT]], float } +// CHECK-DEBUG-DAG: [[S4:%.+]] = type { [[INT]], [[INT]] } +// CHECK-DEBUG-DAG: [[S5:%.+]] = type { [[INT]], [[INT]], [[INT]] } +// CHECK-DEBUG-DAG: [[SMAIN:%.+]] = type { [[INT]], double, double } + +struct S1 { + int a; + S1() + : a(0) { + } + S1(int a) + : a(a) { + } + S1(const S1 &s) { + a = 12 + s.a; + } + ~S1() { + a = 0; + } +}; + +struct S2 { + int a; + double b; + S2() + : a(0) { + } + S2(int a) + : a(a) { + } + S2(const S2 &s) { + a = 12 + s.a; + } + ~S2() { + a = 0; + } +}; + +struct S3 { + int a; + float b; + S3() + : a(0) { + } + S3(int a) + : a(a) { + } + S3(const S3 &s) { + a = 12 + s.a; + } + ~S3() { + a = 0; + } +}; + +struct S4 { + int a, b; + S4() + : a(0) { + } + S4(int a) + : a(a) { + } + S4(const S4 &s) { + a = 12 + s.a; + } + ~S4() { + a = 0; + } +}; + +struct S5 { + int a, b, c; + S5() + : a(0) { + } + S5(int a) + : a(a) { + } + S5(const S5 &s) { + a = 12 + s.a; + } + ~S5() { + a = 0; + } +}; + +// CHECK: [[CACHE1:@[_.0-9a-zA-Z]+]] = common global i8** null +// CHECK-NEXT: [[GS1:@.+]] = internal global [[S1]] zeroinitializer +// CHECK: [[DEFAULT_LOC:@.+]] = private unnamed_addr constant [[IDENT]] { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([{{[0-9]+}} x i8]* {{@.+}}, i32 0, i32 0) } +// CHECK-NOT: {{@.+}} = common global i8** null +// CHECK: [[GS2:@.+]] = internal global [[S2]] zeroinitializer +// CHECK: [[CACHE2:@[_.0-9a-zA-Z]+]] = common global i8** null +// CHECK-NEXT: [[ARR_X:@.+]] = global [2 x [3 x [[S1]]]] zeroinitializer +// CHECK: [[CACHE3:@[_.0-9a-zA-Z]+]] = common global i8** null +// CHECK-NEXT: [[SM:@.+]] = internal global [[SMAIN]] zeroinitializer +// CHECK: [[CACHE4:@[_.0-9a-zA-Z]+]] = common global i8** null +// CHECK-NEXT: [[STATIC_S:@.+]] = external global [[S3]] +// CHECK: [[CACHE5:@[_.0-9a-zA-Z]+]] = common global i8** null +// CHECK-NEXT: [[GS3:@.+]] = external global [[S5]] +// CHECK: [[CACHE6:@[_.0-9a-zA-Z]+]] = common global i8** null +// CHECK-NEXT: [[ST_INT_ST:@.+]] = linkonce_odr global i32 23 +// CHECK: [[CACHE7:@[_.0-9a-zA-Z]+]] = common global i8** null +// CHECK-NEXT: [[ST_FLOAT_ST:@.+]] = linkonce_odr global float 2.300000e+01 +// CHECK: [[CACHE8:@[_.0-9a-zA-Z]+]] = common global i8** null +// CHECK-NEXT: [[ST_S4_ST:@.+]] = linkonce_odr global %struct.S4 zeroinitializer +// CHECK-NOT: {{@.+}} = common global i8** null +// There is no cache for gs2 - it is not threadprivate. Check that there is only +// 8 caches created (for Static::s, gs1, gs3, arr_x, main::sm, ST::st, +// ST::st, ST::st) +// CHECK-DEBUG-DAG: [[GS1:@.+]] = internal global [[S1]] zeroinitializer +// CHECK-DEBUG-DAG: [[GS2:@.+]] = internal global [[S2]] zeroinitializer +// CHECK-DEBUG-DAG: [[ARR_X:@.+]] = global [2 x [3 x [[S1]]]] zeroinitializer +// CHECK-DEBUG-DAG: [[SM:@.+]] = internal global [[SMAIN]] zeroinitializer +// CHECK-DEBUG-DAG: [[STATIC_S:@.+]] = external global [[S3]] +// CHECK-DEBUG-DAG: [[GS3:@.+]] = external global [[S5]] +// CHECK-DEBUG-DAG: [[ST_INT_ST:@.+]] = linkonce_odr global i32 23 +// CHECK-DEBUG-DAG: [[ST_FLOAT_ST:@.+]] = linkonce_odr global float 2.300000e+01 +// CHECK-DEBUG-DAG: [[ST_S4_ST:@.+]] = linkonce_odr global %struct.S4 zeroinitializer +// CHECK-DEBUG-DAG: [[LOC1:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;155;11;;\00" +// CHECK-DEBUG-DAG: [[LOC2:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;202;4;;\00" +// CHECK-DEBUG-DAG: [[LOC3:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;292;19;;\00" +// CHECK-DEBUG-DAG: [[LOC4:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;292;16;;\00" +// CHECK-DEBUG-DAG: [[LOC5:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;326;9;;\00" +// CHECK-DEBUG-DAG: [[LOC6:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;343;10;;\00" +// CHECK-DEBUG-DAG: [[LOC7:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;360;10;;\00" +// CHECK-DEBUG-DAG: [[LOC8:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;386;10;;\00" +// CHECK-DEBUG-DAG: [[LOC9:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;407;10;;\00" +// CHECK-DEBUG-DAG: [[LOC10:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;422;10;;\00" +// CHECK-DEBUG-DAG: [[LOC11:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;439;27;;\00" +// CHECK-DEBUG-DAG: [[LOC12:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;main;456;10;;\00" +// CHECK-DEBUG-DAG: [[LOC13:@.*]] = private unnamed_addr constant [{{[0-9]+}} x i8] c";{{.*}}threadprivate_codegen.cpp;;264;10;;\00" + +struct Static { + static S3 s; +#pragma omp threadprivate(s) +}; + +static S1 gs1(5); +#pragma omp threadprivate(gs1) +// CHECK: define {{.*}} void [[S1_CTOR:@.*]]([[S1]]* %{{.*}}, +// CHECK: define {{.*}} void [[S1_DTOR:@.*]]([[S1]]* %{{.*}}) +// CHECK: define internal i8* [[GS1_CTOR:@\.__kmpc_global_ctor_\..*]](i8*) +// CHECK: [[RES:%.*]] = bitcast i8* %0 to [[S1]]* +// CHECK-NEXT: call void [[S1_CTOR]]([[S1]]* [[RES]], {{.*}} 5) +// CHECK-NEXT: ret i8* %0 +// CHECK-NEXT: } +// CHECK: define internal void [[GS1_DTOR:@\.__kmpc_global_dtor_\..*]](i8*) +// CHECK: [[RES:%.*]] = bitcast i8* %0 to [[S1]]* +// CHECK-NEXT: call void [[S1_DTOR]]([[S1]]* [[RES]]) +// CHECK-NEXT: ret void +// CHECK-NEXT: } +// CHECK: define internal void [[GS1_INIT:@\.__omp_threadprivate_init_\..*]]() +// CHECK: call void @__kmpc_threadprivate_register([[IDENT]]* [[DEFAULT_LOC]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i8* (i8*)* [[GS1_CTOR]], i8* (i8*, i8*)* null, void (i8*)* [[GS1_DTOR]]) +// CHECK-NEXT: ret void +// CHECK-NEXT: } +// CHECK-DEBUG: define {{.*}} void [[S1_CTOR:@.*]]([[S1]]* %{{.*}}, +// CHECK-DEBUG: define {{.*}} void [[S1_DTOR:@.*]]([[S1]]* %{{.*}}) +// CHECK-DEBUG: define internal i8* [[GS1_CTOR:@\.__kmpc_global_ctor_\..*]](i8*) +// CHECK-DEBUG: [[RES:%.*]] = bitcast i8* %0 to [[S1]]* +// CHECK-DEBUG-NEXT: call void [[S1_CTOR]]([[S1]]* [[RES]], {{.*}} 5) +// CHECK-DEBUG-NEXT: ret i8* %0 +// CHECK-DEBUG-NEXT: } +// CHECK-DEBUG: define internal void [[GS1_DTOR:@\.__kmpc_global_dtor_\..*]](i8*) +// CHECK-DEBUG: [[RES:%.*]] = bitcast i8* %0 to [[S1]]* +// CHECK-DEBUG-NEXT: call void [[S1_DTOR]]([[S1]]* [[RES]]) +// CHECK-DEBUG-NEXT: ret void +// CHECK-DEBUG-NEXT: } +// CHECK-DEBUG: define internal void [[GS1_INIT:@\.__omp_threadprivate_init_\..*]]() +// CHECK-DEBUG: [[KMPC_LOC_ADDR:%.*]] = alloca [[IDENT]] +// CHECK-DEBUG: @__kmpc_global_thread_num +// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 +// CHECK-DEBUG: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC1]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] +// CHECK-DEBUG: call void @__kmpc_threadprivate_register([[IDENT]]* [[KMPC_LOC_ADDR]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i8* (i8*)* [[GS1_CTOR]], i8* (i8*, i8*)* null, void (i8*)* [[GS1_DTOR]]) +// CHECK-DEBUG-NEXT: ret void +// CHECK-DEBUG-NEXT: } +static S2 gs2(27); +// CHECK: define {{.*}} void [[S2_CTOR:@.*]]([[S2]]* %{{.*}}, +// CHECK: define {{.*}} void [[S2_DTOR:@.*]]([[S2]]* %{{.*}}) +// No another call for S2 constructor because it is not threadprivate +// CHECK-NOT: call void [[S2_CTOR]]([[S2]]* +// CHECK-DEBUG: define {{.*}} void [[S2_CTOR:@.*]]([[S2]]* %{{.*}}, +// CHECK-DEBUG: define {{.*}} void [[S2_DTOR:@.*]]([[S2]]* %{{.*}}) +// No another call for S2 constructor because it is not threadprivate +// CHECK-DEBUG-NOT: call void [[S2_CTOR]]([[S2]]* +S1 arr_x[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; +#pragma omp threadprivate(arr_x) +// CHECK: define {{.*}} i8* [[ARR_X_CTOR:@\.__kmpc_global_ctor_\..*]](i8*) +// CHECK: [[RES:%.*]] = bitcast i8* %0 to [2 x [3 x [[S1]]]]* +// CHECK: [[ARR1:%.*]] = getelementptr inbounds [2 x [3 x [[S1]]]]* [[RES]], i{{.*}} 0, i{{.*}} 0 +// CHECK: [[ARR:%.*]] = getelementptr inbounds [3 x [[S1]]]* [[ARR1]], i{{.*}} 0, i{{.*}} 0 +// CHECK: invoke void [[S1_CTOR]]([[S1]]* [[ARR]], [[INT]] 1) +// CHECK: [[ARR_ELEMENT:%.*]] = getelementptr inbounds [[S1]]* [[ARR]], i{{.*}} 1 +// CHECK: invoke void [[S1_CTOR]]([[S1]]* [[ARR_ELEMENT]], [[INT]] 2) +// CHECK: [[ARR_ELEMENT2:%.*]] = getelementptr inbounds [[S1]]* [[ARR_ELEMENT]], i{{.*}} 1 +// CHECK: invoke void [[S1_CTOR]]([[S1]]* [[ARR_ELEMENT2]], [[INT]] 3) +// CHECK: [[ARR_ELEMENT3:%.*]] = getelementptr inbounds [3 x [[S1]]]* [[ARR1]], i{{.*}} 1 +// CHECK: [[ARR_:%.*]] = getelementptr inbounds [3 x [[S1]]]* [[ARR_ELEMENT3]], i{{.*}} 0, i{{.*}} 0 +// CHECK: invoke void [[S1_CTOR]]([[S1]]* [[ARR_]], [[INT]] 4) +// CHECK: [[ARR_ELEMENT:%.*]] = getelementptr inbounds [[S1]]* [[ARR_]], i{{.*}} 1 +// CHECK: invoke void [[S1_CTOR]]([[S1]]* [[ARR_ELEMENT]], [[INT]] 5) +// CHECK: [[ARR_ELEMENT2:%.*]] = getelementptr inbounds [[S1]]* [[ARR_ELEMENT]], i{{.*}} 1 +// CHECK: invoke void [[S1_CTOR]]([[S1]]* [[ARR_ELEMENT2]], [[INT]] 6) +// CHECK: ret i8* %0 +// CHECK: } +// CHECK: define {{.*}} void [[ARR_X_DTOR:@\.__kmpc_global_dtor_\..*]](i8*) +// CHECK: [[ARR_BEGIN:%.*]] = bitcast i8* %0 to [[S1]]* +// CHECK-NEXT: [[ARR_CUR:%.*]] = getelementptr inbounds [[S1]]* [[ARR_BEGIN]], i{{.*}} 6 +// CHECK-NEXT: br label %[[ARR_LOOP:.*]] +// CHECK: {{.*}}[[ARR_LOOP]]{{.*}} +// CHECK-NEXT: [[ARR_ELEMENTPAST:%.*]] = phi [[S1]]* [ [[ARR_CUR]], {{.*}} ], [ [[ARR_ELEMENT:%.*]], {{.*}} ] +// CHECK-NEXT: [[ARR_ELEMENT:%.*]] = getelementptr inbounds [[S1]]* [[ARR_ELEMENTPAST]], i{{.*}} -1 +// CHECK-NEXT: invoke void [[S1_DTOR]]([[S1]]* [[ARR_ELEMENT]]) +// CHECK: [[ARR_DONE:%.*]] = icmp eq [[S1]]* [[ARR_ELEMENT]], [[ARR_BEGIN]] +// CHECK-NEXT: br i1 [[ARR_DONE]], label %[[ARR_EXIT:.*]], label %[[ARR_LOOP]] +// CHECK: {{.*}}[[ARR_EXIT]]{{.*}} +// CHECK-NEXT: ret void +// CHECK: } +// CHECK: define {{.*}} void [[ARR_X_INIT:@\.__omp_threadprivate_init_\..*]]() +// CHECK: call void @__kmpc_threadprivate_register([[IDENT]]* [[DEFAULT_LOC]], i8* bitcast ([2 x [3 x [[S1]]]]* [[ARR_X]] to i8*), i8* (i8*)* [[ARR_X_CTOR]], i8* (i8*, i8*)* null, void (i8*)* [[ARR_X_DTOR]]) +// CHECK-NEXT: ret void +// CHECK-NEXT: } +// CHECK-DEBUG: define {{.*}} i8* [[ARR_X_CTOR:@\.__kmpc_global_ctor_\..*]](i8*) +// CHECK-DEBUG: } +// CHECK-DEBUG: define {{.*}} void [[ARR_X_DTOR:@\.__kmpc_global_dtor_\..*]](i8*) +// CHECK-DEBUG: } +// CHECK-DEBUG: define {{.*}} void [[ARR_X_INIT:@\.__omp_threadprivate_init_\..*]]() +// CHECK-DEBUG: [[KMPC_LOC_ADDR:%.*]] = alloca [[IDENT]] +// CHECK-DEBUG: @__kmpc_global_thread_num +// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 +// CHECK-DEBUG: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC2]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] +// CHECK-DEBUG: call void @__kmpc_threadprivate_register([[IDENT]]* [[KMPC_LOC_ADDR]], i8* bitcast ([2 x [3 x [[S1]]]]* [[ARR_X]] to i8*), i8* (i8*)* [[ARR_X_CTOR]], i8* (i8*, i8*)* null, void (i8*)* [[ARR_X_DTOR]]) +// CHECK-DEBUG-NEXT: ret void +// CHECK-DEBUG-NEXT: } +extern S5 gs3; +#pragma omp threadprivate(gs3) +// No call for S5 constructor because gs3 has just declaration, not a definition. +// CHECK-NOT: call void {{.*}}([[S5]]* +// CHECK-DEBUG-NOT: call void {{.*}}([[S5]]* + +template +struct ST { + static T st; +#pragma omp threadprivate(st) +}; + +template +T ST::st(23); + +#endif + +#ifdef BODY + +// CHECK: define i32 @main() +// CHECK-DEBUG: define i32 @main() +int main() { + // CHECK-DEBUG: [[KMPC_LOC_ADDR:%.*]] = alloca [[IDENT]] + int Res; + struct Smain { + int a; + double b, c; + Smain() + : a(0) { + } + Smain(int a) + : a(a) { + } + Smain(const Smain &s) { + a = 12 + s.a; + } + ~Smain() { + a = 0; + } + }; + + static Smain sm(gs1.a); +// CHECK: [[THREAD_NUM:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT]]* [[DEFAULT_LOC]]) +// CHECK: call i{{.*}} @__cxa_guard_acquire +// CHECK: [[GS1_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[CACHE1]]) +// CHECK-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]* +// CHECK-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0 +// CHECK-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]] +// CHECK-NEXT: invoke void [[SMAIN_CTOR:.*]]([[SMAIN]]* [[SM]], [[INT]] [[GS1_A]]) +// CHECK: call void @__cxa_guard_release +// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 +// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC3]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] +// CHECK-DEBUG-NEXT: [[THREAD_NUM:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT]]* [[KMPC_LOC_ADDR]]) +// CHECK-DEBUG: call i{{.*}} @__cxa_guard_acquire +// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 +// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC3]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] +// CHECK-DEBUG: [[GS1_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8*** +// CHECK-DEBUG-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]* +// CHECK-DEBUG-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0 +// CHECK-DEBUG-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]] +// CHECK-DEBUG-NEXT: invoke void [[SMAIN_CTOR:.*]]([[SMAIN]]* [[SM]], [[INT]] [[GS1_A]]) +// CHECK-DEBUG: call void @__cxa_guard_release +#pragma omp threadprivate(sm) + // CHECK: [[STATIC_S_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S3]]* [[STATIC_S]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[CACHE4]]) + // CHECK-NEXT: [[STATIC_S_ADDR:%.*]] = bitcast i8* [[STATIC_S_TEMP_ADDR]] to [[S3]]* + // CHECK-NEXT: [[STATIC_S_A_ADDR:%.*]] = getelementptr inbounds [[S3]]* [[STATIC_S_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-NEXT: [[STATIC_S_A:%.*]] = load [[INT]]* [[STATIC_S_A_ADDR]] + // CHECK-NEXT: store [[INT]] [[STATIC_S_A]], [[INT]]* [[RES_ADDR:[^,]+]] + // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 + // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC5]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] + // CHECK-DEBUG-NEXT: [[STATIC_S_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S3]]* [[STATIC_S]] to i8*), i{{.*}} {{[0-9]+}}, i8*** + // CHECK-DEBUG-NEXT: [[STATIC_S_ADDR:%.*]] = bitcast i8* [[STATIC_S_TEMP_ADDR]] to [[S3]]* + // CHECK-DEBUG-NEXT: [[STATIC_S_A_ADDR:%.*]] = getelementptr inbounds [[S3]]* [[STATIC_S_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-DEBUG-NEXT: [[STATIC_S_A:%.*]] = load [[INT]]* [[STATIC_S_A_ADDR]] + // CHECK-DEBUG-NEXT: store [[INT]] [[STATIC_S_A]], [[INT]]* [[RES_ADDR:[^,]+]] + Res = Static::s.a; + // CHECK: [[SM_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[SMAIN]]* [[SM]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[CACHE3]]) + // CHECK-NEXT: [[SM_ADDR:%.*]] = bitcast i8* [[SM_TEMP_ADDR]] to [[SMAIN]]* + // CHECK-NEXT: [[SM_A_ADDR:%.*]] = getelementptr inbounds [[SMAIN]]* [[SM_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-NEXT: [[SM_A:%.*]] = load [[INT]]* [[SM_A_ADDR]] + // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[SM_A]] + // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 + // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC6]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] + // CHECK-DEBUG-NEXT: [[SM_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[SMAIN]]* [[SM]] to i8*), i{{.*}} {{[0-9]+}}, i8*** + // CHECK-DEBUG-NEXT: [[SM_ADDR:%.*]] = bitcast i8* [[SM_TEMP_ADDR]] to [[SMAIN]]* + // CHECK-DEBUG-NEXT: [[SM_A_ADDR:%.*]] = getelementptr inbounds [[SMAIN]]* [[SM_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-DEBUG-NEXT: [[SM_A:%.*]] = load [[INT]]* [[SM_A_ADDR]] + // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[SM_A]] + // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + Res += sm.a; + // CHECK: [[GS1_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[CACHE1]]) + // CHECK-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]* + // CHECK-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]] + // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS1_A]] + // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 + // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC7]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] + // CHECK-DEBUG-NEXT: [[GS1_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8*** + // CHECK-DEBUG-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]* + // CHECK-DEBUG-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-DEBUG-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]] + // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS1_A]] + // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + Res += gs1.a; + // CHECK: [[GS2_A:%.*]] = load [[INT]]* getelementptr inbounds ([[S2]]* [[GS2]], i{{.*}} 0, i{{.*}} 0) + // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS2_A]] + // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-DEBUG: [[GS2_A:%.*]] = load [[INT]]* getelementptr inbounds ([[S2]]* [[GS2]], i{{.*}} 0, i{{.*}} 0) + // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS2_A]] + // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + Res += gs2.a; + // CHECK: [[GS3_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S5]]* [[GS3]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[CACHE5]]) + // CHECK-NEXT: [[GS3_ADDR:%.*]] = bitcast i8* [[GS3_TEMP_ADDR]] to [[S5]]* + // CHECK-NEXT: [[GS3_A_ADDR:%.*]] = getelementptr inbounds [[S5]]* [[GS3_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-NEXT: [[GS3_A:%.*]] = load [[INT]]* [[GS3_A_ADDR]] + // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS3_A]] + // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 + // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC8]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] + // CHECK-DEBUG-NEXT: [[GS3_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S5]]* [[GS3]] to i8*), i{{.*}} {{[0-9]+}}, i8*** + // CHECK-DEBUG-NEXT: [[GS3_ADDR:%.*]] = bitcast i8* [[GS3_TEMP_ADDR]] to [[S5]]* + // CHECK-DEBUG-NEXT: [[GS3_A_ADDR:%.*]] = getelementptr inbounds [[S5]]* [[GS3_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-DEBUG-NEXT: [[GS3_A:%.*]] = load [[INT]]* [[GS3_A_ADDR]] + // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[GS3_A]] + // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + Res += gs3.a; + // CHECK: [[ARR_X_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([2 x [3 x [[S1]]]]* [[ARR_X]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[CACHE2]]) + // CHECK-NEXT: [[ARR_X_ADDR:%.*]] = bitcast i8* [[ARR_X_TEMP_ADDR]] to [2 x [3 x [[S1]]]]* + // CHECK-NEXT: [[ARR_X_1_ADDR:%.*]] = getelementptr inbounds [2 x [3 x [[S1]]]]* [[ARR_X_ADDR]], i{{.*}} 0, i{{.*}} 1 + // CHECK-NEXT: [[ARR_X_1_1_ADDR:%.*]] = getelementptr inbounds [3 x [[S1]]]* [[ARR_X_1_ADDR]], i{{.*}} 0, i{{.*}} 1 + // CHECK-NEXT: [[ARR_X_1_1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[ARR_X_1_1_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-NEXT: [[ARR_X_1_1_A:%.*]] = load [[INT]]* [[ARR_X_1_1_A_ADDR]] + // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ARR_X_1_1_A]] + // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 + // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC9]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] + // CHECK-DEBUG-NEXT: [[ARR_X_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([2 x [3 x [[S1]]]]* [[ARR_X]] to i8*), i{{.*}} {{[0-9]+}}, i8*** + // CHECK-DEBUG-NEXT: [[ARR_X_ADDR:%.*]] = bitcast i8* [[ARR_X_TEMP_ADDR]] to [2 x [3 x [[S1]]]]* + // CHECK-DEBUG-NEXT: [[ARR_X_1_ADDR:%.*]] = getelementptr inbounds [2 x [3 x [[S1]]]]* [[ARR_X_ADDR]], i{{.*}} 0, i{{.*}} 1 + // CHECK-DEBUG-NEXT: [[ARR_X_1_1_ADDR:%.*]] = getelementptr inbounds [3 x [[S1]]]* [[ARR_X_1_ADDR]], i{{.*}} 0, i{{.*}} 1 + // CHECK-DEBUG-NEXT: [[ARR_X_1_1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[ARR_X_1_1_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-DEBUG-NEXT: [[ARR_X_1_1_A:%.*]] = load [[INT]]* [[ARR_X_1_1_A_ADDR]] + // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ARR_X_1_1_A]] + // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + Res += arr_x[1][1].a; + // CHECK: [[ST_INT_ST_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[INT]]* [[ST_INT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[CACHE6]]) + // CHECK-NEXT: [[ST_INT_ST_ADDR:%.*]] = bitcast i8* [[ST_INT_ST_TEMP_ADDR]] to [[INT]]* + // CHECK-NEXT: [[ST_INT_ST_VAL:%.*]] = load [[INT]]* [[ST_INT_ST_ADDR]] + // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_INT_ST_VAL]] + // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 + // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC10]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] + // CHECK-DEBUG-NEXT: [[ST_INT_ST_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[INT]]* [[ST_INT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** + // CHECK-DEBUG-NEXT: [[ST_INT_ST_ADDR:%.*]] = bitcast i8* [[ST_INT_ST_TEMP_ADDR]] to [[INT]]* + // CHECK-DEBUG-NEXT: [[ST_INT_ST_VAL:%.*]] = load [[INT]]* [[ST_INT_ST_ADDR]] + // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_INT_ST_VAL]] + // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + Res += ST::st; + // CHECK: [[ST_FLOAT_ST_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast (float* [[ST_FLOAT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[CACHE7]]) + // CHECK-NEXT: [[ST_FLOAT_ST_ADDR:%.*]] = bitcast i8* [[ST_FLOAT_ST_TEMP_ADDR]] to float* + // CHECK-NEXT: [[ST_FLOAT_ST_VAL:%.*]] = load float* [[ST_FLOAT_ST_ADDR]] + // CHECK-NEXT: [[FLOAT_TO_INT_CONV:%.*]] = fptosi float [[ST_FLOAT_ST_VAL]] to [[INT]] + // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[FLOAT_TO_INT_CONV]] + // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 + // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC11]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] + // CHECK-DEBUG-NEXT: [[ST_FLOAT_ST_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast (float* [[ST_FLOAT_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** + // CHECK-DEBUG-NEXT: [[ST_FLOAT_ST_ADDR:%.*]] = bitcast i8* [[ST_FLOAT_ST_TEMP_ADDR]] to float* + // CHECK-DEBUG-NEXT: [[ST_FLOAT_ST_VAL:%.*]] = load float* [[ST_FLOAT_ST_ADDR]] + // CHECK-DEBUG-NEXT: [[FLOAT_TO_INT_CONV:%.*]] = fptosi float [[ST_FLOAT_ST_VAL]] to [[INT]] + // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[FLOAT_TO_INT_CONV]] + // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + Res += static_cast(ST::st); + // CHECK: [[ST_S4_ST_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[CACHE8]]) + // CHECK-NEXT: [[ST_S4_ST_ADDR:%.*]] = bitcast i8* [[ST_S4_ST_TEMP_ADDR]] to [[S4]]* + // CHECK-NEXT: [[ST_S4_ST_A_ADDR:%.*]] = getelementptr inbounds [[S4]]* [[ST_S4_ST_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-NEXT: [[ST_S4_ST_A:%.*]] = load [[INT]]* [[ST_S4_ST_A_ADDR]] + // CHECK-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_S4_ST_A]] + // CHECK-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + // CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 + // CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC12]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] + // CHECK-DEBUG-NEXT: [[ST_S4_ST_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*), i{{.*}} {{[0-9]+}}, i8*** + // CHECK-DEBUG-NEXT: [[ST_S4_ST_ADDR:%.*]] = bitcast i8* [[ST_S4_ST_TEMP_ADDR]] to [[S4]]* + // CHECK-DEBUG-NEXT: [[ST_S4_ST_A_ADDR:%.*]] = getelementptr inbounds [[S4]]* [[ST_S4_ST_ADDR]], i{{.*}} 0, i{{.*}} 0 + // CHECK-DEBUG-NEXT: [[ST_S4_ST_A:%.*]] = load [[INT]]* [[ST_S4_ST_A_ADDR]] + // CHECK-DEBUG-NEXT: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-DEBUG-NEXT: [[ADD:%.*]] = add {{.*}} [[INT]] [[RES]], [[ST_S4_ST_A]] + // CHECK-DEBUG-NEXT: store [[INT]] [[ADD]], [[INT]]* [[RES:.+]] + Res += ST::st.a; + // CHECK: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-NEXT: ret [[INT]] [[RES]] + // CHECK-DEBUG: [[RES:%.*]] = load [[INT]]* [[RES_ADDR]] + // CHECK-DEBUG-NEXT: ret [[INT]] [[RES]] + return Res; +} +// CHECK: } + +// CHECK: define {{.*}} void [[SMAIN_CTOR]]([[SMAIN]]* %{{.*}}, +// CHECK: define {{.*}} void [[SMAIN_DTOR:@.*]]([[SMAIN]]* %{{.*}}) +// CHECK: define internal i8* [[SM_CTOR:@\.__kmpc_global_ctor_\..*]](i8*) +// CHECK: [[THREAD_NUM:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT]]* [[DEFAULT_LOC]]) +// CHECK: [[RES:%.*]] = bitcast i8* %0 to [[SMAIN]]* +// CHECK: [[GS1_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[DEFAULT_LOC]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8*** [[CACHE1]]) +// CHECK-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]* +// CHECK-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0 +// CHECK-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]] +// CHECK-NEXT: call void [[SMAIN_CTOR]]([[SMAIN]]* [[RES]], [[INT]] [[GS1_A]]) +// CHECK-NEXT: ret i8* %0 +// CHECK-NEXT: } +// CHECK: define internal void [[SM_DTOR:@\.__kmpc_global_dtor_\..*]](i8*) +// CHECK: [[RES:%.*]] = bitcast i8* %0 to [[SMAIN]]* +// CHECK-NEXT: call void [[SMAIN_DTOR]]([[SMAIN]]* [[RES]]) +// CHECK-NEXT: ret void +// CHECK-NEXT: } +// CHECK: define internal void [[SM_INIT:@\.__omp_threadprivate_init_\..*]]() +// CHECK: call void @__kmpc_threadprivate_register([[IDENT]]* [[DEFAULT_LOC]], i8* bitcast ([[SMAIN]]* [[SM]] to i8*), i8* (i8*)* [[SM_CTOR]], i8* (i8*, i8*)* null, void (i8*)* [[SM_DTOR]]) +// CHECK-NEXT: ret void +// CHECK-NEXT: } +// CHECK-DEBUG: define {{.*}} void [[SMAIN_CTOR]]([[SMAIN]]* %{{.*}}, +// CHECK-DEBUG: define {{.*}} void [[SMAIN_DTOR:@.*]]([[SMAIN]]* %{{.*}}) +// CHECK-DEBUG: define internal i8* [[SM_CTOR:@\.__kmpc_global_ctor_\..*]](i8*) +// CHECK-DEBUG: [[KMPC_LOC_ADDR:%.*]] = alloca [[IDENT]] +// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 +// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC3]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] +// CHECK-DEBUG-NEXT: [[THREAD_NUM:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT]]* [[KMPC_LOC_ADDR]]) +// CHECK-DEBUG: [[RES:%.*]] = bitcast i8* %0 to [[SMAIN]]* +// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 +// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC3]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] +// CHECK-DEBUG: [[GS1_TEMP_ADDR:%.*]] = call i8* @__kmpc_threadprivate_cached([[IDENT]]* [[KMPC_LOC_ADDR]], i32 [[THREAD_NUM]], i8* bitcast ([[S1]]* [[GS1]] to i8*), i{{.*}} {{[0-9]+}}, i8*** +// CHECK-DEBUG-NEXT: [[GS1_ADDR:%.*]] = bitcast i8* [[GS1_TEMP_ADDR]] to [[S1]]* +// CHECK-DEBUG-NEXT: [[GS1_A_ADDR:%.*]] = getelementptr inbounds [[S1]]* [[GS1_ADDR]], i{{.*}} 0, i{{.*}} 0 +// CHECK-DEBUG-NEXT: [[GS1_A:%.*]] = load [[INT]]* [[GS1_A_ADDR]] +// CHECK-DEBUG-NEXT: call void [[SMAIN_CTOR]]([[SMAIN]]* [[RES]], [[INT]] [[GS1_A]]) +// CHECK-DEBUG-NEXT: ret i8* %0 +// CHECK-DEBUG-NEXT: } +// CHECK-DEBUG: define internal void [[SM_DTOR:@\.__kmpc_global_dtor_\..*]](i8*) +// CHECK-DEBUG: } +// CHECK-DEBUG: define internal void [[SM_INIT:@\.__omp_threadprivate_init_\..*]]() +// CHECK-DEBUG: [[KMPC_LOC_ADDR:%.*]] = alloca [[IDENT]] +// CHECK-DEBUG: @__kmpc_global_thread_num +// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 +// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC4]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] +// CHECK-DEBUG: call void @__kmpc_threadprivate_register([[IDENT]]* [[KMPC_LOC_ADDR]], i8* bitcast ([[SMAIN]]* [[SM]] to i8*), i8* (i8*)* [[SM_CTOR]], i8* (i8*, i8*)* null, void (i8*)* [[SM_DTOR]]) +// CHECK-DEBUG-NEXT: ret void +// CHECK-DEBUG-NEXT: } + +// CHECK: define {{.*}} void [[S4_CTOR:@.*]]([[S4]]* %{{.*}}, +// CHECK: define {{.*}} void [[S4_DTOR:@.*]]([[S4]]* %{{.*}}) +// CHECK: define internal i8* [[ST_S4_ST_CTOR:@\.__kmpc_global_ctor_\..*]](i8*) +// CHECK: [[RES:%.*]] = bitcast i8* %0 to [[S4]]* +// CHECK-NEXT: call void [[S4_CTOR]]([[S4]]* [[RES]], {{.*}} 23) +// CHECK-NEXT: ret i8* %0 +// CHECK-NEXT: } +// CHECK: define internal void [[ST_S4_ST_DTOR:@\.__kmpc_global_dtor_\..*]](i8*) +// CHECK: [[RES:%.*]] = bitcast i8* %0 to [[S4]]* +// CHECK-NEXT: call void [[S4_DTOR]]([[S4]]* [[RES]]) +// CHECK-NEXT: ret void +// CHECK-NEXT: } +// CHECK: define internal void [[ST_S4_ST_INIT:@\.__omp_threadprivate_init_\..*]]() +// CHECK: call void @__kmpc_threadprivate_register([[IDENT]]* [[DEFAULT_LOC]], i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*), i8* (i8*)* [[ST_S4_ST_CTOR]], i8* (i8*, i8*)* null, void (i8*)* [[ST_S4_ST_DTOR]]) +// CHECK-NEXT: ret void +// CHECK-NEXT: } +// CHECK-DEBUG: define {{.*}} void [[S4_CTOR:@.*]]([[S4]]* %{{.*}}, +// CHECK-DEBUG: define {{.*}} void [[S4_DTOR:@.*]]([[S4]]* %{{.*}}) +// CHECK-DEBUG: define internal i8* [[ST_S4_ST_CTOR:@\.__kmpc_global_ctor_\..*]](i8*) +// CHECK-DEBUG: } +// CHECK-DEBUG: define internal void [[ST_S4_ST_DTOR:@\.__kmpc_global_dtor_\..*]](i8*) +// CHECK-DEBUG: } +// CHECK-DEBUG: define internal void [[ST_S4_ST_INIT:@\.__omp_threadprivate_init_\..*]]() +// CHECK-DEBUG: [[KMPC_LOC_ADDR:%.*]] = alloca [[IDENT]] +// CHECK-DEBUG: @__kmpc_global_thread_num +// CHECK-DEBUG: [[KMPC_LOC_ADDR_PSOURCE:%.*]] = getelementptr inbounds [[IDENT]]* [[KMPC_LOC_ADDR]], i{{.*}} 0, i{{.*}} 4 +// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.*}} x i8]* [[LOC13]], i{{.*}} 0, i{{.*}} 0), i8** [[KMPC_LOC_ADDR_PSOURCE]] +// CHECK-DEBUG: call void @__kmpc_threadprivate_register([[IDENT]]* [[KMPC_LOC_ADDR]], i8* bitcast ([[S4]]* [[ST_S4_ST]] to i8*), i8* (i8*)* [[ST_S4_ST_CTOR]], i8* (i8*, i8*)* null, void (i8*)* [[ST_S4_ST_DTOR]]) +// CHECK-DEBUG-NEXT: ret void +// CHECK-DEBUG-NEXT: } + +// CHECK: define internal void {{@.*}}() +// CHECK-DAG: call void [[GS1_INIT]]() +// CHECK-DAG: call void [[ARR_X_INIT]]() +// CHECK-DAG: call void [[SM_INIT]]() +// CHECK-DAG: call void [[ST_S4_ST_INIT]]() +// CHECK: ret void +// CHECK-DEBUG: define internal void {{@.*}}() +// CHECK-DEBUG-DAG: call void [[GS1_INIT]]() +// CHECK-DEBUG-DAG: call void [[ARR_X_INIT]]() +// CHECK-DEBUG-DAG: call void [[SM_INIT]]() +// CHECK-DEBUG-DAG: call void [[ST_S4_ST_INIT]]() +// CHECK-DEBUG: ret void +#endif +