From aac108a324dd0478afa349cd756c2a7c4d6e97ea Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Tue, 23 Jun 2015 04:51:00 +0000 Subject: [PATCH] [OPENMP] Do not emit references to original variables in 'private' clause. Currently if the variable is captured in captured region, capture record for this region stores reference to this variable for future use. But we don't need to provide the reference to the original variable if it was explicitly marked as private in the 'private' clause of the OpenMP construct, this variable is replaced by private copy. Differential Revision: http://reviews.llvm.org/D9550 llvm-svn: 240377 --- clang/include/clang/Sema/Sema.h | 10 +++- clang/lib/Parse/ParseOpenMP.cpp | 4 +- clang/lib/Sema/SemaExpr.cpp | 15 ++++++ clang/lib/Sema/SemaOpenMP.cpp | 50 +++++++++++++++---- clang/lib/Sema/TreeTransform.h | 2 + clang/test/OpenMP/for_private_codegen.cpp | 5 +- .../test/OpenMP/parallel_private_codegen.cpp | 14 +++--- .../test/OpenMP/sections_private_codegen.cpp | 4 +- clang/test/OpenMP/single_private_codegen.cpp | 4 +- clang/test/OpenMP/task_private_codegen.cpp | 45 ++++------------- 10 files changed, 90 insertions(+), 63 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 07d65f459ab1..84318c3b9427 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7605,6 +7605,12 @@ private: bool IsOpenMPCapturedVar(VarDecl *VD); public: + /// \brief Check if the specified variable is used in one of the private + /// clauses in OpenMP constructs. + /// \param Level Relative level of nested OpenMP construct for that the check + /// is performed. + bool isOpenMPPrivateVar(VarDecl *VD, unsigned Level); + ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op); /// \brief Called on start of new data sharing attribute block. @@ -7612,9 +7618,9 @@ public: const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc); /// \brief Start analysis of clauses. - void StartOpenMPClauses(); + void StartOpenMPClause(OpenMPClauseKind K); /// \brief End analysis of clauses. - void EndOpenMPClauses(); + void EndOpenMPClause(); /// \brief Called on end of data sharing attribute block. void EndOpenMPDSABlock(Stmt *CurDirective); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index a3c3c5dc7d49..a721fcca01c6 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -226,13 +226,13 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) { ParseScope OMPDirectiveScope(this, ScopeFlags); Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc); - Actions.StartOpenMPClauses(); while (Tok.isNot(tok::annot_pragma_openmp_end)) { OpenMPClauseKind CKind = Tok.isAnnotation() ? OMPC_unknown : FlushHasClause ? OMPC_flush : getOpenMPClauseKind(PP.getSpelling(Tok)); + Actions.StartOpenMPClause(CKind); FlushHasClause = false; OMPClause *Clause = ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt()); @@ -245,8 +245,8 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) { // Skip ',' if any. if (Tok.is(tok::comma)) ConsumeToken(); + Actions.EndOpenMPClause(); } - Actions.EndOpenMPClauses(); // End location of the directive. EndLoc = Tok.getLocation(); // Consume final annot_pragma_openmp_end. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ffa47eeb5871..2d2cadab9a37 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -12741,6 +12741,7 @@ bool Sema::tryCaptureVariable( bool Nested = false; bool Explicit = (Kind != TryCapture_Implicit); unsigned FunctionScopesIndex = MaxFunctionScopesIndex; + unsigned OpenMPLevel = 0; do { // Only block literals, captured statements, and lambda expressions can // capture; other scopes don't work. @@ -12767,6 +12768,20 @@ bool Sema::tryCaptureVariable( if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType, DeclRefType)) break; + if (getLangOpts().OpenMP) { + if (auto *RSI = dyn_cast(CSI)) { + // OpenMP private variables should not be captured in outer scope, so + // just break here. + if (RSI->CapRegionKind == CR_OpenMP) { + if (isOpenMPPrivateVar(Var, OpenMPLevel)) { + Nested = true; + CaptureType = Context.getLValueReferenceType(DeclRefType); + break; + } + ++OpenMPLevel; + } + } + } // If we are instantiating a generic lambda call operator body, // we do not want to capture new variables. What was captured // during either a lambdas transformation or initial parsing diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index e609fcf1d9be..5028ac5fa7b2 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -116,7 +116,7 @@ private: StackTy Stack; /// \brief true, if check for DSA must be from parent directive, false, if /// from current directive. - bool FromParent; + OpenMPClauseKind ClauseKindMode; Sema &SemaRef; typedef SmallVector::reverse_iterator reverse_iterator; @@ -127,10 +127,11 @@ private: bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter); public: - explicit DSAStackTy(Sema &S) : Stack(1), FromParent(false), SemaRef(S) {} + explicit DSAStackTy(Sema &S) + : Stack(1), ClauseKindMode(OMPC_unknown), SemaRef(S) {} - bool isFromParent() const { return FromParent; } - void setFromParent(bool Flag) { FromParent = Flag; } + bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; } + void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; } void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc) { @@ -175,6 +176,12 @@ public: DSAVarData hasInnermostDSA(VarDecl *D, ClausesPredicate CPred, DirectivesPredicate DPred, bool FromParent); + /// \brief Checks if the specified variables has explicit data-sharing + /// attributes which match specified \a CPred predicate at the specified + /// OpenMP region. + bool hasExplicitDSA(VarDecl *D, + const llvm::function_ref &CPred, + unsigned Level); /// \brief Finds a directive which matches specified \a DPred predicate. template bool hasDirective(NamedDirectivesPredicate DPred, bool FromParent); @@ -589,6 +596,23 @@ DSAStackTy::hasInnermostDSA(VarDecl *D, ClausesPredicate CPred, return DSAVarData(); } +bool DSAStackTy::hasExplicitDSA( + VarDecl *D, const llvm::function_ref &CPred, + unsigned Level) { + if (CPred(ClauseKindMode)) + return true; + if (isClauseParsingMode()) + ++Level; + D = D->getCanonicalDecl(); + auto StartI = Stack.rbegin(); + auto EndI = std::prev(Stack.rend()); + if (std::distance(StartI, EndI) <= Level) + return false; + std::advance(StartI, Level); + return (StartI->SharingMap.count(D) > 0) && StartI->SharingMap[D].RefExpr && + CPred(StartI->SharingMap[D].Attributes); +} + template bool DSAStackTy::hasDirective(NamedDirectivesPredicate DPred, bool FromParent) { auto StartI = std::next(Stack.rbegin()); @@ -617,16 +641,22 @@ bool Sema::IsOpenMPCapturedVar(VarDecl *VD) { (VD->hasLocalStorage() && isParallelOrTaskRegion(DSAStack->getCurrentDirective()))) return true; - auto DVarPrivate = DSAStack->getTopDSA(VD, DSAStack->isFromParent()); + auto DVarPrivate = DSAStack->getTopDSA(VD, DSAStack->isClauseParsingMode()); if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) return true; DVarPrivate = DSAStack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), - DSAStack->isFromParent()); + DSAStack->isClauseParsingMode()); return DVarPrivate.CKind != OMPC_unknown; } return false; } +bool Sema::isOpenMPPrivateVar(VarDecl *VD, unsigned Level) { + assert(LangOpts.OpenMP && "OpenMP is not allowed"); + return DSAStack->hasExplicitDSA( + VD, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, Level); +} + void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, @@ -636,12 +666,12 @@ void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, PushExpressionEvaluationContext(PotentiallyEvaluated); } -void Sema::StartOpenMPClauses() { - DSAStack->setFromParent(/*Flag=*/true); +void Sema::StartOpenMPClause(OpenMPClauseKind K) { + DSAStack->setClauseParsingMode(K); } -void Sema::EndOpenMPClauses() { - DSAStack->setFromParent(/*Flag=*/false); +void Sema::EndOpenMPClause() { + DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown); } void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 73dde7c97fc2..322cb6ccb584 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -6664,7 +6664,9 @@ StmtResult TreeTransform::TransformOMPExecutableDirective( for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); I != E; ++I) { if (*I) { + getDerived().getSema().StartOpenMPClause((*I)->getClauseKind()); OMPClause *Clause = getDerived().TransformOMPClause(*I); + getDerived().getSema().EndOpenMPClause(); if (Clause) TClauses.push_back(Clause); } else { diff --git a/clang/test/OpenMP/for_private_codegen.cpp b/clang/test/OpenMP/for_private_codegen.cpp index 8fc5fe7a18b0..f217b9ac5d7b 100644 --- a/clang/test/OpenMP/for_private_codegen.cpp +++ b/clang/test/OpenMP/for_private_codegen.cpp @@ -19,9 +19,10 @@ struct S { volatile double g; // CHECK: [[S_FLOAT_TY:%.+]] = type { float } -// CHECK: [[CAP_MAIN_TY:%.+]] = type { i{{[0-9]+}}*, [2 x i{{[0-9]+}}]*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]* } +// CHECK: [[CAP_MAIN_TY:%.+]] = type { i8 } +// CHECK: type { i8 } // CHECK: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} } -// CHECK: [[CAP_TMAIN_TY:%.+]] = type { i{{[0-9]+}}*, [2 x i{{[0-9]+}}]*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* } +// CHECK: [[CAP_TMAIN_TY:%.+]] = type { i8 } template T tmain() { S test; diff --git a/clang/test/OpenMP/parallel_private_codegen.cpp b/clang/test/OpenMP/parallel_private_codegen.cpp index 99e2d4d404db..21de26cd419e 100644 --- a/clang/test/OpenMP/parallel_private_codegen.cpp +++ b/clang/test/OpenMP/parallel_private_codegen.cpp @@ -19,9 +19,9 @@ struct 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: [[CAP_MAIN_TY:%.+]] = type { i8 } // CHECK: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} } -// CHECK: [[CAP_TMAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* } +// CHECK: [[CAP_TMAIN_TY:%.+]] = type { i8 } template T tmain() { S test; @@ -44,9 +44,8 @@ int main() { // LAMBDA: call{{( x86_thiscallcc)?}} 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-NOT: = getelementptr inbounds %{{.+}}, + // LAMBDA: [[ARG:%.+]] = bitcast %{{.+}}* %{{.+}} to i8* // LAMBDA: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) #pragma omp parallel private(g) { @@ -76,9 +75,8 @@ int 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-NOT: = getelementptr inbounds %{{.+}}, + // BLOCKS: [[ARG:%.+]] = bitcast %{{.+}}* %{{.+}} to i8* // BLOCKS: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) #pragma omp parallel private(g) { diff --git a/clang/test/OpenMP/sections_private_codegen.cpp b/clang/test/OpenMP/sections_private_codegen.cpp index 4bad714908d2..95d67707721b 100644 --- a/clang/test/OpenMP/sections_private_codegen.cpp +++ b/clang/test/OpenMP/sections_private_codegen.cpp @@ -19,9 +19,9 @@ struct S { volatile double g; // CHECK: [[S_FLOAT_TY:%.+]] = type { float } -// CHECK: [[CAP_MAIN_TY:%.+]] = type { i{{[0-9]+}}*, [2 x i{{[0-9]+}}]*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]* } +// CHECK: [[CAP_MAIN_TY:%.+]] = type { i8 } // CHECK: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} } -// CHECK: [[CAP_TMAIN_TY:%.+]] = type { i{{[0-9]+}}*, [2 x i{{[0-9]+}}]*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* } +// CHECK: [[CAP_TMAIN_TY:%.+]] = type { i8 } template T tmain() { S test; diff --git a/clang/test/OpenMP/single_private_codegen.cpp b/clang/test/OpenMP/single_private_codegen.cpp index 4f78d082b82b..b0155058fc21 100644 --- a/clang/test/OpenMP/single_private_codegen.cpp +++ b/clang/test/OpenMP/single_private_codegen.cpp @@ -19,9 +19,9 @@ struct S { volatile double g; // CHECK: [[S_FLOAT_TY:%.+]] = type { float } -// CHECK: [[CAP_MAIN_TY:%.+]] = type { i{{[0-9]+}}*, [2 x i{{[0-9]+}}]*, [2 x [[S_FLOAT_TY]]]*, [[S_FLOAT_TY]]* } +// CHECK: [[CAP_MAIN_TY:%.+]] = type { i8 } // CHECK: [[S_INT_TY:%.+]] = type { i{{[0-9]+}} } -// CHECK: [[CAP_TMAIN_TY:%.+]] = type { i{{[0-9]+}}*, [2 x i{{[0-9]+}}]*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* } +// CHECK: [[CAP_TMAIN_TY:%.+]] = type { i8 } template T tmain() { S test; diff --git a/clang/test/OpenMP/task_private_codegen.cpp b/clang/test/OpenMP/task_private_codegen.cpp index 3a9ed7c58d63..463913f926a4 100644 --- a/clang/test/OpenMP/task_private_codegen.cpp +++ b/clang/test/OpenMP/task_private_codegen.cpp @@ -26,11 +26,11 @@ volatile double g; // CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, i32 (i32, i8*)* } // CHECK-DAG: [[S_DOUBLE_TY:%.+]] = type { double } -// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type { [2 x i32]*, i32*, [2 x [[S_DOUBLE_TY]]]*, [[S_DOUBLE_TY]]* } +// CHECK-DAG: [[CAP_MAIN_TY:%.+]] = type { i8 } // CHECK-DAG: [[PRIVATES_MAIN_TY:%.+]] = type {{.?}}{ [[S_DOUBLE_TY]], [2 x [[S_DOUBLE_TY]]], i32, [2 x i32] // CHECK-DAG: [[KMP_TASK_MAIN_TY:%.+]] = type { [[KMP_TASK_T_TY]], [[PRIVATES_MAIN_TY]] } // CHECK-DAG: [[S_INT_TY:%.+]] = type { i32 } -// CHECK-DAG: [[CAP_TMAIN_TY:%.+]] = type { [2 x i32]*, i32*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* } +// CHECK-DAG: [[CAP_TMAIN_TY:%.+]] = type { i8 } // CHECK-DAG: [[PRIVATES_TMAIN_TY:%.+]] = type { i32, [2 x i32], [2 x [[S_INT_TY]]], [[S_INT_TY]] } // CHECK-DAG: [[KMP_TASK_TMAIN_TY:%.+]] = type { [[KMP_TASK_T_TY]], [[PRIVATES_TMAIN_TY]] } template @@ -55,7 +55,7 @@ int main() { // LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]]( [&]() { // LAMBDA: define{{.*}} internal{{.*}} void [[OUTER_LAMBDA]]( - // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 40, i64 8, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*)) + // LAMBDA: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 40, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*)) // LAMBDA: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1 // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[PRIVATES]], i{{.+}} 0, i{{.+}} 0 // LAMBDA: call i32 @__kmpc_omp_task(%{{.+}}* @{{.+}}, i32 %{{.+}}, i8* [[RES]]) @@ -86,7 +86,7 @@ int main() { // BLOCKS: call void {{%.+}}(i8 ^{ // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8* - // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 40, i64 8, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*)) + // BLOCKS: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc(%{{[^ ]+}} @{{[^,]+}}, i32 %{{[^,]+}}, i32 1, i64 40, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, %{{[^*]+}}*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*)) // BLOCKS: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1 // BLOCKS: [[G_PRIVATE_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[PRIVATES]], i{{.+}} 0, i{{.+}} 0 // BLOCKS: call i32 @__kmpc_omp_task(%{{.+}}* @{{.+}}, i32 %{{.+}}, i8* [[RES]]) @@ -135,31 +135,18 @@ int main() { // CHECK: call {{.*}} [[S_DOUBLE_TY_DEF_CONSTR:@.+]]([[S_DOUBLE_TY]]* [[TEST]]) -// Store original variables in capture struct. -// CHECK: [[VEC_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0 -// CHECK: store [2 x i32]* [[VEC_ADDR]], [2 x i32]** [[VEC_REF]], -// CHECK: [[T_VAR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1 -// CHECK: store i32* [[T_VAR_ADDR]], i32** [[T_VAR_REF]], -// CHECK: [[S_ARR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2 -// CHECK: store [2 x [[S_DOUBLE_TY]]]* [[S_ARR_ADDR]], [2 x [[S_DOUBLE_TY]]]** [[S_ARR_REF]], -// CHECK: [[VAR_REF:%.+]] = getelementptr inbounds [[CAP_MAIN_TY]], [[CAP_MAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3 -// CHECK: store [[S_DOUBLE_TY]]* [[VAR_ADDR]], [[S_DOUBLE_TY]]** [[VAR_REF]], +// Do not store original variables in capture struct. +// CHECK-NOT: getelementptr inbounds [[CAP_MAIN_TY]], // Allocate task. // Returns struct kmp_task_t { // [[KMP_TASK_T_TY]] task_data; // [[KMP_TASK_MAIN_TY]] privates; // }; -// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 1, i64 72, i64 32, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*)) +// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 1, i64 72, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_MAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*)) // CHECK: [[RES_KMP_TASK:%.+]] = bitcast i8* [[RES]] to [[KMP_TASK_MAIN_TY]]* -// Fill kmp_task_t->shareds by copying from original capture argument. // CHECK: [[TASK:%.+]] = getelementptr inbounds [[KMP_TASK_MAIN_TY]], [[KMP_TASK_MAIN_TY]]* [[RES_KMP_TASK]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 -// CHECK: [[SHAREDS_REF_ADDR:%.+]] = getelementptr inbounds [[KMP_TASK_T_TY]], [[KMP_TASK_T_TY]]* [[TASK]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 -// CHECK: [[SHAREDS_REF:%.+]] = load i8*, i8** [[SHAREDS_REF_ADDR]], -// CHECK: [[CAPTURES_ADDR:%.+]] = bitcast [[CAP_MAIN_TY]]* %{{.+}} to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[SHAREDS_REF]], i8* [[CAPTURES_ADDR]], i64 32, i32 8, i1 false) - // Initialize kmp_task_t->privates with default values (no init for simple types, default constructors for classes). // Also copy address of private copy to the corresponding shareds reference. // CHECK: [[PRIVATES:%.+]] = getelementptr inbounds [[KMP_TASK_MAIN_TY]], [[KMP_TASK_MAIN_TY]]* [[RES_KMP_TASK]], i{{[0-9]+}} 0, i{{[0-9]+}} 1 @@ -257,30 +244,18 @@ int main() { // CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]]) -// Store original variables in capture struct. -// CHECK: [[VEC_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 0 -// CHECK: store [2 x i32]* [[VEC_ADDR]], [2 x i32]** [[VEC_REF]], -// CHECK: [[T_VAR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 1 -// CHECK: store i32* [[T_VAR_ADDR]], i32** [[T_VAR_REF]], -// CHECK: [[S_ARR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 2 -// CHECK: store [2 x [[S_INT_TY]]]* [[S_ARR_ADDR]], [2 x [[S_INT_TY]]]** [[S_ARR_REF]], -// CHECK: [[VAR_REF:%.+]] = getelementptr inbounds [[CAP_TMAIN_TY]], [[CAP_TMAIN_TY]]* %{{.+}}, i{{[0-9]+}} 0, i{{[0-9]+}} 3 -// CHECK: store [[S_INT_TY]]* [[VAR_ADDR]], [[S_INT_TY]]** [[VAR_REF]], +// Do not store original variables in capture struct. +// CHECK-NOT: getelementptr inbounds [[CAP_TMAIN_TY]], // Allocate task. // Returns struct kmp_task_t { // [[KMP_TASK_T_TY]] task_data; // [[KMP_TASK_TMAIN_TY]] privates; // }; -// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 1, i64 56, i64 32, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_TMAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*)) +// CHECK: [[RES:%.+]] = call i8* @__kmpc_omp_task_alloc([[LOC]], i32 [[GTID]], i32 1, i64 56, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[KMP_TASK_TMAIN_TY]]*)* [[TASK_ENTRY:@[^ ]+]] to i32 (i32, i8*)*)) // CHECK: [[RES_KMP_TASK:%.+]] = bitcast i8* [[RES]] to [[KMP_TASK_TMAIN_TY]]* -// Fill kmp_task_t->shareds by copying from original capture argument. // CHECK: [[TASK:%.+]] = getelementptr inbounds [[KMP_TASK_TMAIN_TY]], [[KMP_TASK_TMAIN_TY]]* [[RES_KMP_TASK]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 -// CHECK: [[SHAREDS_REF_ADDR:%.+]] = getelementptr inbounds [[KMP_TASK_T_TY]], [[KMP_TASK_T_TY]]* [[TASK]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 -// CHECK: [[SHAREDS_REF:%.+]] = load i8*, i8** [[SHAREDS_REF_ADDR]], -// CHECK: [[CAPTURES_ADDR:%.+]] = bitcast [[CAP_TMAIN_TY]]* %{{.+}} to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[SHAREDS_REF]], i8* [[CAPTURES_ADDR]], i64 32, i32 8, i1 false) // Initialize kmp_task_t->privates with default values (no init for simple types, default constructors for classes). // CHECK: [[PRIVATES:%.+]] = getelementptr inbounds [[KMP_TASK_TMAIN_TY]], [[KMP_TASK_TMAIN_TY]]* [[RES_KMP_TASK]], i{{[0-9]+}} 0, i{{[0-9]+}} 1