[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
This commit is contained in:
Alexey Bataev 2015-06-23 04:51:00 +00:00
parent 9ad0ec295f
commit aac108a324
10 changed files with 90 additions and 63 deletions

View File

@ -7605,6 +7605,12 @@ private:
bool IsOpenMPCapturedVar(VarDecl *VD); bool IsOpenMPCapturedVar(VarDecl *VD);
public: 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, ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc,
Expr *Op); Expr *Op);
/// \brief Called on start of new data sharing attribute block. /// \brief Called on start of new data sharing attribute block.
@ -7612,9 +7618,9 @@ public:
const DeclarationNameInfo &DirName, Scope *CurScope, const DeclarationNameInfo &DirName, Scope *CurScope,
SourceLocation Loc); SourceLocation Loc);
/// \brief Start analysis of clauses. /// \brief Start analysis of clauses.
void StartOpenMPClauses(); void StartOpenMPClause(OpenMPClauseKind K);
/// \brief End analysis of clauses. /// \brief End analysis of clauses.
void EndOpenMPClauses(); void EndOpenMPClause();
/// \brief Called on end of data sharing attribute block. /// \brief Called on end of data sharing attribute block.
void EndOpenMPDSABlock(Stmt *CurDirective); void EndOpenMPDSABlock(Stmt *CurDirective);

View File

@ -226,13 +226,13 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
ParseScope OMPDirectiveScope(this, ScopeFlags); ParseScope OMPDirectiveScope(this, ScopeFlags);
Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc); Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc);
Actions.StartOpenMPClauses();
while (Tok.isNot(tok::annot_pragma_openmp_end)) { while (Tok.isNot(tok::annot_pragma_openmp_end)) {
OpenMPClauseKind CKind = OpenMPClauseKind CKind =
Tok.isAnnotation() Tok.isAnnotation()
? OMPC_unknown ? OMPC_unknown
: FlushHasClause ? OMPC_flush : FlushHasClause ? OMPC_flush
: getOpenMPClauseKind(PP.getSpelling(Tok)); : getOpenMPClauseKind(PP.getSpelling(Tok));
Actions.StartOpenMPClause(CKind);
FlushHasClause = false; FlushHasClause = false;
OMPClause *Clause = OMPClause *Clause =
ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt()); ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt());
@ -245,8 +245,8 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
// Skip ',' if any. // Skip ',' if any.
if (Tok.is(tok::comma)) if (Tok.is(tok::comma))
ConsumeToken(); ConsumeToken();
Actions.EndOpenMPClause();
} }
Actions.EndOpenMPClauses();
// End location of the directive. // End location of the directive.
EndLoc = Tok.getLocation(); EndLoc = Tok.getLocation();
// Consume final annot_pragma_openmp_end. // Consume final annot_pragma_openmp_end.

View File

@ -12741,6 +12741,7 @@ bool Sema::tryCaptureVariable(
bool Nested = false; bool Nested = false;
bool Explicit = (Kind != TryCapture_Implicit); bool Explicit = (Kind != TryCapture_Implicit);
unsigned FunctionScopesIndex = MaxFunctionScopesIndex; unsigned FunctionScopesIndex = MaxFunctionScopesIndex;
unsigned OpenMPLevel = 0;
do { do {
// Only block literals, captured statements, and lambda expressions can // Only block literals, captured statements, and lambda expressions can
// capture; other scopes don't work. // capture; other scopes don't work.
@ -12767,6 +12768,20 @@ bool Sema::tryCaptureVariable(
if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType, if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType,
DeclRefType)) DeclRefType))
break; break;
if (getLangOpts().OpenMP) {
if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(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, // If we are instantiating a generic lambda call operator body,
// we do not want to capture new variables. What was captured // we do not want to capture new variables. What was captured
// during either a lambdas transformation or initial parsing // during either a lambdas transformation or initial parsing

View File

@ -116,7 +116,7 @@ private:
StackTy Stack; StackTy Stack;
/// \brief true, if check for DSA must be from parent directive, false, if /// \brief true, if check for DSA must be from parent directive, false, if
/// from current directive. /// from current directive.
bool FromParent; OpenMPClauseKind ClauseKindMode;
Sema &SemaRef; Sema &SemaRef;
typedef SmallVector<SharingMapTy, 8>::reverse_iterator reverse_iterator; typedef SmallVector<SharingMapTy, 8>::reverse_iterator reverse_iterator;
@ -127,10 +127,11 @@ private:
bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter); bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter);
public: 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; } bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; }
void setFromParent(bool Flag) { FromParent = Flag; } void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; }
void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName,
Scope *CurScope, SourceLocation Loc) { Scope *CurScope, SourceLocation Loc) {
@ -175,6 +176,12 @@ public:
DSAVarData hasInnermostDSA(VarDecl *D, ClausesPredicate CPred, DSAVarData hasInnermostDSA(VarDecl *D, ClausesPredicate CPred,
DirectivesPredicate DPred, DirectivesPredicate DPred,
bool FromParent); 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<bool(OpenMPClauseKind)> &CPred,
unsigned Level);
/// \brief Finds a directive which matches specified \a DPred predicate. /// \brief Finds a directive which matches specified \a DPred predicate.
template <class NamedDirectivesPredicate> template <class NamedDirectivesPredicate>
bool hasDirective(NamedDirectivesPredicate DPred, bool FromParent); bool hasDirective(NamedDirectivesPredicate DPred, bool FromParent);
@ -589,6 +596,23 @@ DSAStackTy::hasInnermostDSA(VarDecl *D, ClausesPredicate CPred,
return DSAVarData(); return DSAVarData();
} }
bool DSAStackTy::hasExplicitDSA(
VarDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &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 <class NamedDirectivesPredicate> template <class NamedDirectivesPredicate>
bool DSAStackTy::hasDirective(NamedDirectivesPredicate DPred, bool FromParent) { bool DSAStackTy::hasDirective(NamedDirectivesPredicate DPred, bool FromParent) {
auto StartI = std::next(Stack.rbegin()); auto StartI = std::next(Stack.rbegin());
@ -617,16 +641,22 @@ bool Sema::IsOpenMPCapturedVar(VarDecl *VD) {
(VD->hasLocalStorage() && (VD->hasLocalStorage() &&
isParallelOrTaskRegion(DSAStack->getCurrentDirective()))) isParallelOrTaskRegion(DSAStack->getCurrentDirective())))
return true; return true;
auto DVarPrivate = DSAStack->getTopDSA(VD, DSAStack->isFromParent()); auto DVarPrivate = DSAStack->getTopDSA(VD, DSAStack->isClauseParsingMode());
if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind))
return true; return true;
DVarPrivate = DSAStack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), DVarPrivate = DSAStack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(),
DSAStack->isFromParent()); DSAStack->isClauseParsingMode());
return DVarPrivate.CKind != OMPC_unknown; return DVarPrivate.CKind != OMPC_unknown;
} }
return false; 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::DestroyDataSharingAttributesStack() { delete DSAStack; }
void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
@ -636,12 +666,12 @@ void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
PushExpressionEvaluationContext(PotentiallyEvaluated); PushExpressionEvaluationContext(PotentiallyEvaluated);
} }
void Sema::StartOpenMPClauses() { void Sema::StartOpenMPClause(OpenMPClauseKind K) {
DSAStack->setFromParent(/*Flag=*/true); DSAStack->setClauseParsingMode(K);
} }
void Sema::EndOpenMPClauses() { void Sema::EndOpenMPClause() {
DSAStack->setFromParent(/*Flag=*/false); DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown);
} }
void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {

View File

@ -6664,7 +6664,9 @@ StmtResult TreeTransform<Derived>::TransformOMPExecutableDirective(
for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end(); for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
I != E; ++I) { I != E; ++I) {
if (*I) { if (*I) {
getDerived().getSema().StartOpenMPClause((*I)->getClauseKind());
OMPClause *Clause = getDerived().TransformOMPClause(*I); OMPClause *Clause = getDerived().TransformOMPClause(*I);
getDerived().getSema().EndOpenMPClause();
if (Clause) if (Clause)
TClauses.push_back(Clause); TClauses.push_back(Clause);
} else { } else {

View File

@ -19,9 +19,10 @@ struct S {
volatile double g; volatile double g;
// CHECK: [[S_FLOAT_TY:%.+]] = type { float } // 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: [[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 <typename T> template <typename T>
T tmain() { T tmain() {
S<T> test; S<T> test;

View File

@ -19,9 +19,9 @@ struct S {
volatile int g = 1212; volatile int g = 1212;
// CHECK: [[S_FLOAT_TY:%.+]] = type { float } // 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: [[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 <typename T> template <typename T>
T tmain() { T tmain() {
S<T> test; S<T> test;
@ -44,9 +44,8 @@ int main() {
// LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]]( // LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]](
[&]() { [&]() {
// LAMBDA: define{{.*}} internal{{.*}} 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-NOT: = getelementptr inbounds %{{.+}},
// LAMBDA: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]] // LAMBDA: [[ARG:%.+]] = bitcast %{{.+}}* %{{.+}} to i8*
// LAMBDA: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8*
// LAMBDA: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) // LAMBDA: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
#pragma omp parallel private(g) #pragma omp parallel private(g)
{ {
@ -76,9 +75,8 @@ int main() {
// BLOCKS: call void {{%.+}}(i8 // BLOCKS: call void {{%.+}}(i8
^{ ^{
// BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8* // BLOCKS: define{{.*}} internal{{.*}} void {{.+}}(i8*
// BLOCKS: [[G_LOCAL_REF:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[AGG_CAPTURED:%.+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0 // BLOCKS-NOT: = getelementptr inbounds %{{.+}},
// BLOCKS: store i{{[0-9]+}}* [[G]], i{{[0-9]+}}** [[G_LOCAL_REF]] // BLOCKS: [[ARG:%.+]] = bitcast %{{.+}}* %{{.+}} to i8*
// BLOCKS: [[ARG:%.+]] = bitcast %{{.+}}* [[AGG_CAPTURED]] to i8*
// BLOCKS: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]]) // BLOCKS: call void {{.+}} @__kmpc_fork_call({{.+}}, i32 1, {{.+}}* [[OMP_REGION:@.+]] to {{.+}}, i8* [[ARG]])
#pragma omp parallel private(g) #pragma omp parallel private(g)
{ {

View File

@ -19,9 +19,9 @@ struct S {
volatile double g; volatile double g;
// CHECK: [[S_FLOAT_TY:%.+]] = type { float } // 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: [[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 <typename T> template <typename T>
T tmain() { T tmain() {
S<T> test; S<T> test;

View File

@ -19,9 +19,9 @@ struct S {
volatile double g; volatile double g;
// CHECK: [[S_FLOAT_TY:%.+]] = type { float } // 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: [[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 <typename T> template <typename T>
T tmain() { T tmain() {
S<T> test; S<T> test;

View File

@ -26,11 +26,11 @@ volatile double g;
// CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, i32 (i32, i8*)* } // CHECK-DAG: [[KMP_TASK_T_TY:%.+]] = type { i8*, i32 (i32, i8*)*, i32, i32 (i32, i8*)* }
// CHECK-DAG: [[S_DOUBLE_TY:%.+]] = type { double } // 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: [[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: [[KMP_TASK_MAIN_TY:%.+]] = type { [[KMP_TASK_T_TY]], [[PRIVATES_MAIN_TY]] }
// CHECK-DAG: [[S_INT_TY:%.+]] = type { i32 } // 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: [[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]] } // CHECK-DAG: [[KMP_TASK_TMAIN_TY:%.+]] = type { [[KMP_TASK_T_TY]], [[PRIVATES_TMAIN_TY]] }
template <typename T> template <typename T>
@ -55,7 +55,7 @@ int main() {
// LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]]( // LAMBDA: call{{( x86_thiscallcc)?}} void [[OUTER_LAMBDA:@.+]](
[&]() { [&]() {
// LAMBDA: define{{.*}} internal{{.*}} 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: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// LAMBDA: [[G_PRIVATE_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[PRIVATES]], i{{.+}} 0, i{{.+}} 0 // LAMBDA: [[G_PRIVATE_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[PRIVATES]], i{{.+}} 0, i{{.+}} 0
// LAMBDA: call i32 @__kmpc_omp_task(%{{.+}}* @{{.+}}, i32 %{{.+}}, i8* [[RES]]) // LAMBDA: call i32 @__kmpc_omp_task(%{{.+}}* @{{.+}}, i32 %{{.+}}, i8* [[RES]])
@ -86,7 +86,7 @@ int main() {
// BLOCKS: call void {{%.+}}(i8 // BLOCKS: call void {{%.+}}(i8
^{ ^{
// BLOCKS: define{{.*}} internal{{.*}} 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: [[PRIVATES:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i{{.+}} 0, i{{.+}} 1
// BLOCKS: [[G_PRIVATE_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[PRIVATES]], i{{.+}} 0, i{{.+}} 0 // BLOCKS: [[G_PRIVATE_ADDR:%.+]] = getelementptr inbounds %{{.+}}, %{{.+}}* [[PRIVATES]], i{{.+}} 0, i{{.+}} 0
// BLOCKS: call i32 @__kmpc_omp_task(%{{.+}}* @{{.+}}, i32 %{{.+}}, i8* [[RES]]) // 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]]) // CHECK: call {{.*}} [[S_DOUBLE_TY_DEF_CONSTR:@.+]]([[S_DOUBLE_TY]]* [[TEST]])
// Store original variables in capture struct. // Do not 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-NOT: getelementptr inbounds [[CAP_MAIN_TY]],
// 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]],
// Allocate task. // Allocate task.
// Returns struct kmp_task_t { // Returns struct kmp_task_t {
// [[KMP_TASK_T_TY]] task_data; // [[KMP_TASK_T_TY]] task_data;
// [[KMP_TASK_MAIN_TY]] privates; // [[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]]* // 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: [[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). // 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. // 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 // 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]]) // CHECK: call {{.*}} [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
// Store original variables in capture struct. // Do not 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-NOT: getelementptr inbounds [[CAP_TMAIN_TY]],
// 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]],
// Allocate task. // Allocate task.
// Returns struct kmp_task_t { // Returns struct kmp_task_t {
// [[KMP_TASK_T_TY]] task_data; // [[KMP_TASK_T_TY]] task_data;
// [[KMP_TASK_TMAIN_TY]] privates; // [[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]]* // 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: [[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). // 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 // CHECK: [[PRIVATES:%.+]] = getelementptr inbounds [[KMP_TASK_TMAIN_TY]], [[KMP_TASK_TMAIN_TY]]* [[RES_KMP_TASK]], i{{[0-9]+}} 0, i{{[0-9]+}} 1