Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -3448,6 +3448,9 @@ TryCaptureKind Kind = TryCapture_Implicit, SourceLocation EllipsisLoc = SourceLocation()); + /// \brief Checks if the variable must be captured. + bool NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc); + /// \brief Given a variable, determine the type that a reference to that /// variable will have in the given scope. QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc); @@ -7482,6 +7485,10 @@ void DestroyDataSharingAttributesStack(); ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind); + /// \brief Checks if the specified variable is used in one of the private + /// clauses in OpenMP constructs. + bool IsOpenMPCapturedVar(VarDecl *VD); + public: ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op); Index: cfe/trunk/lib/CodeGen/CGExpr.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGExpr.cpp +++ cfe/trunk/lib/CodeGen/CGExpr.cpp @@ -1906,6 +1906,21 @@ QualType T = E->getType(); if (const auto *VD = dyn_cast(ND)) { + // Check for captured variables. + if (E->refersToEnclosingLocal()) { + if (auto *FD = LambdaCaptureFields.lookup(VD)) + return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue); + else if (CapturedStmtInfo) { + if (auto *V = LocalDeclMap.lookup(VD)) + return MakeAddrLValue(V, T, Alignment); + else + return EmitCapturedFieldLValue(*this, CapturedStmtInfo->lookup(VD), + CapturedStmtInfo->getContextValue()); + } else + return MakeAddrLValue(GetAddrOfBlockDecl(VD, VD->hasAttr()), + T, Alignment); + } + // Global Named registers access via intrinsics only if (VD->getStorageClass() == SC_Register && VD->hasAttr() && !VD->isLocalVarDecl()) @@ -1956,21 +1971,6 @@ *this, VD, T, V, getTypes().ConvertTypeForMem(VD->getType()), Alignment, E->getExprLoc()); - // Use special handling for lambdas. - if (!V) { - if (FieldDecl *FD = LambdaCaptureFields.lookup(VD)) { - return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue); - } else if (CapturedStmtInfo) { - if (const FieldDecl *FD = CapturedStmtInfo->lookup(VD)) - return EmitCapturedFieldLValue(*this, FD, - CapturedStmtInfo->getContextValue()); - } - - assert(isa(CurCodeDecl) && E->refersToEnclosingLocal()); - return MakeAddrLValue(GetAddrOfBlockDecl(VD, isBlockVariable), - T, Alignment); - } - assert(V && "DeclRefExpr not entered in LocalDeclMap?"); if (isBlockVariable) Index: cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp +++ cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp @@ -20,6 +20,35 @@ using namespace clang; using namespace CodeGen; +namespace { +/// \brief RAII for emitting code of CapturedStmt without function outlining. +class InlinedOpenMPRegion { + CodeGenFunction &CGF; + CodeGenFunction::CGCapturedStmtInfo *PrevCapturedStmtInfo; + const Decl *StoredCurCodeDecl; + + /// \brief A class to emit CapturedStmt construct as inlined statement without + /// generating a function for outlined code. + class CGInlinedOpenMPRegionInfo : public CodeGenFunction::CGCapturedStmtInfo { + public: + CGInlinedOpenMPRegionInfo() : CGCapturedStmtInfo() {} + }; + +public: + InlinedOpenMPRegion(CodeGenFunction &CGF, const Stmt *S) + : CGF(CGF), PrevCapturedStmtInfo(CGF.CapturedStmtInfo), + StoredCurCodeDecl(CGF.CurCodeDecl) { + CGF.CurCodeDecl = cast(S)->getCapturedDecl(); + CGF.CapturedStmtInfo = new CGInlinedOpenMPRegionInfo(); + } + ~InlinedOpenMPRegion() { + delete CGF.CapturedStmtInfo; + CGF.CapturedStmtInfo = PrevCapturedStmtInfo; + CGF.CurCodeDecl = StoredCurCodeDecl; + } +}; +} // namespace + //===----------------------------------------------------------------------===// // OpenMP Directive Emission //===----------------------------------------------------------------------===// @@ -417,6 +446,7 @@ } } + InlinedOpenMPRegion Region(*this, S.getAssociatedStmt()); RunCleanupsScope DirectiveScope(*this); CGDebugInfo *DI = getDebugInfo(); @@ -561,6 +591,7 @@ } void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) { + InlinedOpenMPRegion Region(*this, S.getAssociatedStmt()); RunCleanupsScope DirectiveScope(*this); CGDebugInfo *DI = getDebugInfo(); @@ -593,8 +624,8 @@ } void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) { - CGM.getOpenMPRuntime().EmitOMPMasterRegion( - *this, [&]() -> void { + CGM.getOpenMPRuntime().EmitOMPMasterRegion(*this, [&]() -> void { + InlinedOpenMPRegion Region(*this, S.getAssociatedStmt()); RunCleanupsScope Scope(*this); EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); EnsureInsertPoint(); @@ -604,8 +635,10 @@ void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) { CGM.getOpenMPRuntime().EmitOMPCriticalRegion( *this, S.getDirectiveName().getAsString(), [&]() -> void { + InlinedOpenMPRegion Region(*this, S.getAssociatedStmt()); RunCleanupsScope Scope(*this); - EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); + EmitStmt( + cast(S.getAssociatedStmt())->getCapturedStmt()); EnsureInsertPoint(); }, S.getLocStart()); } Index: cfe/trunk/lib/CodeGen/CodeGenFunction.h =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.h +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h @@ -182,6 +182,8 @@ /// \brief API for captured statement code generation. class CGCapturedStmtInfo { public: + explicit CGCapturedStmtInfo(CapturedRegionKind K = CR_Default) + : Kind(K), ThisValue(nullptr), CXXThisFieldDecl(nullptr) {} explicit CGCapturedStmtInfo(const CapturedStmt &S, CapturedRegionKind K = CR_Default) : Kind(K), ThisValue(nullptr), CXXThisFieldDecl(nullptr) { @@ -614,7 +616,6 @@ addPrivate(const VarDecl *LocalVD, const std::function &PrivateGen) { assert(PerformCleanup && "adding private to dead scope"); - assert(LocalVD->isLocalVarDecl() && "privatizing non-local variable"); if (SavedLocals.count(LocalVD) > 0) return false; SavedLocals[LocalVD] = CGF.LocalDeclMap.lookup(LocalVD); CGF.LocalDeclMap.erase(LocalVD); Index: cfe/trunk/lib/Frontend/Rewrite/RewriteModernObjC.cpp =================================================================== --- cfe/trunk/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ cfe/trunk/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -4563,16 +4563,12 @@ GetBlockDeclRefExprs(*CI); } // Handle specific things. - if (DeclRefExpr *DRE = dyn_cast(S)) { - if (DRE->refersToEnclosingLocal()) { + if (DeclRefExpr *DRE = dyn_cast(S)) + if (DRE->refersToEnclosingLocal() || + HasLocalVariableExternalStorage(DRE->getDecl())) // FIXME: Handle enums. - if (!isa(DRE->getDecl())) - BlockDeclRefs.push_back(DRE); - if (HasLocalVariableExternalStorage(DRE->getDecl())) - BlockDeclRefs.push_back(DRE); - } - } - + BlockDeclRefs.push_back(DRE); + return; } @@ -4595,11 +4591,11 @@ } // Handle specific things. if (DeclRefExpr *DRE = dyn_cast(S)) { - if (DRE->refersToEnclosingLocal()) { - if (!isa(DRE->getDecl()) && - !InnerContexts.count(DRE->getDecl()->getDeclContext())) + if (DRE->refersToEnclosingLocal() || + HasLocalVariableExternalStorage(DRE->getDecl())) { + if (!InnerContexts.count(DRE->getDecl()->getDeclContext())) InnerBlockDeclRefs.push_back(DRE); - if (VarDecl *Var = dyn_cast(DRE->getDecl())) + if (VarDecl *Var = cast(DRE->getDecl())) if (Var->isFunctionOrMethodVarDecl()) ImportedLocalExternalDecls.insert(Var); } @@ -4776,7 +4772,8 @@ // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR // for each DeclRefExp where BYREFVAR is name of the variable. ValueDecl *VD = DeclRefExp->getDecl(); - bool isArrow = DeclRefExp->refersToEnclosingLocal(); + bool isArrow = DeclRefExp->refersToEnclosingLocal() || + HasLocalVariableExternalStorage(DeclRefExp->getDecl()); FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(), Index: cfe/trunk/lib/Frontend/Rewrite/RewriteObjC.cpp =================================================================== --- cfe/trunk/lib/Frontend/Rewrite/RewriteObjC.cpp +++ cfe/trunk/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -3671,16 +3671,12 @@ GetBlockDeclRefExprs(*CI); } // Handle specific things. - if (DeclRefExpr *DRE = dyn_cast(S)) { - if (DRE->refersToEnclosingLocal()) { + if (DeclRefExpr *DRE = dyn_cast(S)) + if (DRE->refersToEnclosingLocal() || + HasLocalVariableExternalStorage(DRE->getDecl())) // FIXME: Handle enums. - if (!isa(DRE->getDecl())) - BlockDeclRefs.push_back(DRE); - if (HasLocalVariableExternalStorage(DRE->getDecl())) - BlockDeclRefs.push_back(DRE); - } - } - + BlockDeclRefs.push_back(DRE); + return; } @@ -3703,11 +3699,11 @@ } // Handle specific things. if (DeclRefExpr *DRE = dyn_cast(S)) { - if (DRE->refersToEnclosingLocal()) { - if (!isa(DRE->getDecl()) && - !InnerContexts.count(DRE->getDecl()->getDeclContext())) + if (DRE->refersToEnclosingLocal() || + HasLocalVariableExternalStorage(DRE->getDecl())) { + if (!InnerContexts.count(DRE->getDecl()->getDeclContext())) InnerBlockDeclRefs.push_back(DRE); - if (VarDecl *Var = dyn_cast(DRE->getDecl())) + if (VarDecl *Var = cast(DRE->getDecl())) if (Var->isFunctionOrMethodVarDecl()) ImportedLocalExternalDecls.insert(Var); } @@ -3865,7 +3861,8 @@ // Rewrite the byref variable into BYREFVAR->__forwarding->BYREFVAR // for each DeclRefExp where BYREFVAR is name of the variable. ValueDecl *VD = DeclRefExp->getDecl(); - bool isArrow = DeclRefExp->refersToEnclosingLocal(); + bool isArrow = DeclRefExp->refersToEnclosingLocal() || + HasLocalVariableExternalStorage(DeclRefExp->getDecl()); FieldDecl *FD = FieldDecl::Create(*Context, nullptr, SourceLocation(), SourceLocation(), Index: cfe/trunk/lib/Sema/SemaExpr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp +++ cfe/trunk/lib/Sema/SemaExpr.cpp @@ -1602,10 +1602,8 @@ } bool refersToEnclosingScope = - (CurContext != D->getDeclContext() && - D->getDeclContext()->isFunctionOrMethod()) || - (isa(D) && - cast(D)->isInitCapture()); + isa(D) && + NeedToCaptureVariable(cast(D), NameInfo.getLoc()); DeclRefExpr *E; if (isa(D)) { @@ -11799,7 +11797,7 @@ const bool Diagnose, Sema &S) { if (isa(DC) || isa(DC) || isLambdaCallOperator(DC)) return getLambdaAwareParentOfDeclContext(DC); - else { + else if (Var->hasLocalStorage()) { if (Diagnose) diagnoseUncapturableValueReference(S, Loc, Var, DC); } @@ -12241,7 +12239,7 @@ QualType &CaptureType, QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) { - bool Nested = false; + bool Nested = Var->isInitCapture(); DeclContext *DC = CurContext; const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt @@ -12259,8 +12257,13 @@ // If the variable is declared in the current context (and is not an // init-capture), there is no need to capture it. - if (!Var->isInitCapture() && Var->getDeclContext() == DC) return true; - if (!Var->hasLocalStorage()) return true; + if (!Nested && Var->getDeclContext() == DC) return true; + + // Capture global variables if it is required to use private copy of this + // variable. + bool IsGlobal = !Var->hasLocalStorage(); + if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedVar(Var))) + return true; // Walk up the stack to determine whether we can capture the variable, // performing the "simple" checks that don't depend on type. We stop when @@ -12281,8 +12284,17 @@ ExprLoc, BuildAndDiagnose, *this); - if (!ParentDC) return true; - + // We need to check for the parent *first* because, if we *have* + // private-captured a global variable, we need to recursively capture it in + // intermediate blocks, lambdas, etc. + if (!ParentDC) { + if (IsGlobal) { + FunctionScopesIndex = MaxFunctionScopesIndex - 1; + break; + } + return true; + } + FunctionScopeInfo *FSI = FunctionScopes[FunctionScopesIndex]; CapturingScopeInfo *CSI = cast(FSI); @@ -12508,6 +12520,14 @@ DeclRefType, nullptr); } +bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) { + QualType CaptureType; + QualType DeclRefType; + return !tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(), + /*BuildAndDiagnose=*/false, CaptureType, + DeclRefType, nullptr); +} + QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) { QualType CaptureType; QualType DeclRefType; Index: cfe/trunk/lib/Sema/SemaOpenMP.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaOpenMP.cpp +++ cfe/trunk/lib/Sema/SemaOpenMP.cpp @@ -551,6 +551,19 @@ #define DSAStack static_cast(VarDataSharingAttributesStack) +bool Sema::IsOpenMPCapturedVar(VarDecl *VD) { + assert(LangOpts.OpenMP && "OpenMP is not allowed"); + if (DSAStack->getCurrentDirective() != OMPD_unknown) { + auto DVarPrivate = DSAStack->getTopDSA(VD, /*FromParent=*/false); + if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) + return true; + DVarPrivate = DSAStack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), + /*FromParent=*/false); + return DVarPrivate.CKind != OMPC_unknown; + } + return false; +} + void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, @@ -4378,7 +4391,7 @@ VDInitRefExpr = DeclRefExpr::Create( Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), /*TemplateKWLoc*/ SourceLocation(), VDInit, - /*isEnclosingLocal*/ false, ELoc, Type, + /*isEnclosingLocal*/ true, ELoc, Type, /*VK*/ VK_LValue); VDInit->setIsUsed(); auto Init = DefaultLvalueConversion(VDInitRefExpr).get(); @@ -4392,8 +4405,14 @@ else VDPrivate->setInit(Result.getAs()); } else { - AddInitializerToDecl(VDPrivate, DefaultLvalueConversion(DE).get(), - /*DirectInit*/ false, /*TypeMayContainAuto*/ false); + AddInitializerToDecl( + VDPrivate, DefaultLvalueConversion( + DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), + SourceLocation(), DE->getDecl(), + /*isEnclosingLocal=*/true, + DE->getExprLoc(), DE->getType(), + /*VK=*/VK_LValue)).get(), + /*DirectInit=*/false, /*TypeMayContainAuto=*/false); } if (VDPrivate->isInvalidDecl()) { if (IsImplicitClause) { Index: cfe/trunk/test/OpenMP/parallel_firstprivate_codegen.cpp =================================================================== --- cfe/trunk/test/OpenMP/parallel_firstprivate_codegen.cpp +++ cfe/trunk/test/OpenMP/parallel_firstprivate_codegen.cpp @@ -1,6 +1,8 @@ // RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple %itanium_abi_triple -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics #ifndef HEADER #define HEADER @@ -12,7 +14,7 @@ ~St() {} }; -volatile int g; +volatile int g = 1212; template struct S { @@ -47,6 +49,83 @@ } int main() { +#ifdef LAMBDA + // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212, + // LAMBDA-LABEL: @main + // LAMBDA: call void [[OUTER_LAMBDA:@.+]]( + [&]() { + // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]]( + // LAMBDA: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]] + // LAMBDA: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8* + // LAMBDA: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) +#pragma omp parallel firstprivate(g) + { + // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]]) + // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, + // LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], + // LAMBDA: [[ARG:%.+]] = load %{{.+}}** [[ARG_REF]] + // LAMBDA: [[G_REF_ADDR:%.+]] = getelementptr inbounds %{{.+}}* [[ARG]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}** [[G_REF_ADDR]] + // LAMBDA: [[G_VAL:%.+]] = load volatile i{{[0-9]+}}* [[G_REF]] + // LAMBDA: store volatile i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]] + // LAMBDA: call i32 @__kmpc_cancel_barrier( + g = 1; + // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]] + // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) + [&]() { + // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]]) + // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]], + g = 2; + // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}** [[ARG_PTR_REF]] + // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}** [[G_PTR_REF]] + // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] + }(); + } + }(); + return 0; +#elif defined(BLOCKS) + // BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212, + // BLOCKS-LABEL: @main + // BLOCKS: call void {{%.+}}(i8* + ^{ + // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8* + // BLOCKS: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // BLOCKS: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]] + // BLOCKS: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8* + // BLOCKS: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) +#pragma omp parallel firstprivate(g) + { + // BLOCKS: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]]) + // BLOCKS: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, + // BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], + // BLOCKS: [[ARG:%.+]] = load %{{.+}}** [[ARG_REF]] + // BLOCKS: [[G_REF_ADDR:%.+]] = getelementptr inbounds %{{.+}}* [[ARG]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // BLOCKS: [[G_REF:%.+]] = load i{{[0-9]+}}** [[G_REF_ADDR]] + // BLOCKS: [[G_VAL:%.+]] = load volatile i{{[0-9]+}}* [[G_REF]] + // BLOCKS: store volatile i{{[0-9]+}} [[G_VAL]], i{{[0-9]+}}* [[G_PRIVATE_ADDR]] + // BLOCKS: call i32 @__kmpc_cancel_barrier( + g = 1; + // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]] + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: call void {{%.+}}(i8* + ^{ + // BLOCKS: define {{.+}} void {{@.+}}(i8* + g = 2; + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: ret + }(); + } + }(); + return 0; +#else S test; int t_var = 0; int vec[] = {1, 2}; @@ -58,6 +137,7 @@ s_arr[0] = var; } return tmain(); +#endif } // CHECK: define {{.*}}i{{[0-9]+}} @main() Index: cfe/trunk/test/OpenMP/parallel_private_codegen.cpp =================================================================== --- cfe/trunk/test/OpenMP/parallel_private_codegen.cpp +++ cfe/trunk/test/OpenMP/parallel_private_codegen.cpp @@ -1,6 +1,8 @@ // RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s // RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple x86_64-unknown-unknown -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -std=c++11 -DLAMBDA -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s +// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -fblocks -DBLOCKS -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s // expected-no-diagnostics #ifndef HEADER #define HEADER @@ -14,6 +16,8 @@ ~S() {} }; +volatile int g = 1212; + // CHECK: [[S_FLOAT_TY:%.+]] = type { float } // CHECK: [[CAP_MAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]* } // CHECK: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} } @@ -22,7 +26,7 @@ template T tmain() { S test; - T t_var; + T t_var = T(); T vec[] = {1, 2}; S s_arr[] = {1, 2}; S var(3); @@ -35,8 +39,75 @@ } int main() { +#ifdef LAMBDA + // LAMBDA: [[G:@.+]] = global i{{[0-9]+}} 1212, + // LAMBDA-LABEL: @main + // LAMBDA: call void [[OUTER_LAMBDA:@.+]]( + [&]() { + // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]]( + // LAMBDA: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]] + // LAMBDA: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8* + // LAMBDA: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) +#pragma omp parallel private(g) + { + // LAMBDA: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]]) + // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, + // LAMBDA: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], + // LAMBDA: call i32 @__kmpc_cancel_barrier( + g = 1; + // LAMBDA: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // LAMBDA: [[G_PRIVATE_ADDR_REF:%.+]] = getelementptr inbounds %{{.+}}* [[ARG:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: store i{{[0-9]+}}* [[G_PRIVATE_ADDR]], i{{[0-9]+}}** [[G_PRIVATE_ADDR_REF]] + // LAMBDA: call void [[INNER_LAMBDA:@.+]](%{{.+}}* [[ARG]]) + [&]() { + // LAMBDA: define {{.+}} void [[INNER_LAMBDA]](%{{.+}}* [[ARG_PTR:%.+]]) + // LAMBDA: store %{{.+}}* [[ARG_PTR]], %{{.+}}** [[ARG_PTR_REF:%.+]], + g = 2; + // LAMBDA: [[ARG_PTR:%.+]] = load %{{.+}}** [[ARG_PTR_REF]] + // LAMBDA: [[G_PTR_REF:%.+]] = getelementptr inbounds %{{.+}}* [[ARG_PTR]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // LAMBDA: [[G_REF:%.+]] = load i{{[0-9]+}}** [[G_PTR_REF]] + // LAMBDA: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* [[G_REF]] + }(); + } + }(); + return 0; +#elif defined(BLOCKS) + // BLOCKS: [[G:@.+]] = global i{{[0-9]+}} 1212, + // BLOCKS-LABEL: @main + // BLOCKS: call void {{%.+}}(i8* + ^{ + // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8* + // BLOCKS: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 + // BLOCKS: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]] + // BLOCKS: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8* + // BLOCKS: call void {{.+}}* @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) +#pragma omp parallel private(g) + { + // BLOCKS: define{{.*}} internal{{.*}} void [[OMP_REGION]](i32* %{{.+}}, i32* %{{.+}}, %{{.+}}* [[ARG:%.+]]) + // BLOCKS: [[G_PRIVATE_ADDR:%.+]] = alloca i{{[0-9]+}}, + // BLOCKS: store %{{.+}}* [[ARG]], %{{.+}}** [[ARG_REF:%.+]], + // BLOCKS: call i32 @__kmpc_cancel_barrier( + g = 1; + // BLOCKS: store volatile i{{[0-9]+}} 1, i{{[0-9]+}}* [[G_PRIVATE_ADDR]], + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: i{{[0-9]+}}* [[G_PRIVATE_ADDR]] + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: call void {{%.+}}(i8* + ^{ + // BLOCKS: define {{.+}} void {{@.+}}(i8* + g = 2; + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: store volatile i{{[0-9]+}} 2, i{{[0-9]+}}* + // BLOCKS-NOT: [[G]]{{[[^:word:]]}} + // BLOCKS: ret + }(); + } + }(); + return 0; +#else S test; - int t_var; + int t_var = 0; int vec[] = {1, 2}; S s_arr[] = {1, 2}; S var(3); @@ -46,6 +117,7 @@ s_arr[0] = var; } return tmain(); +#endif } // CHECK: define i{{[0-9]+}} @main()