From 909bb897f805a24469c0a1798ea6c1dd9569fe35 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Thu, 17 Mar 2016 10:50:17 +0000 Subject: [PATCH] [OPENMP 4.5] Allow to use private data members in 'copyprivate' clause. OpenMP 4.5 allows privatization of non-static data members in non-static member functions. This patch adds support of private data members in 'copyprivate' clauses. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@263706 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaOpenMP.cpp | 74 +++++----- test/OpenMP/single_ast_print.cpp | 33 ++++- test/OpenMP/single_codegen.cpp | 224 ++++++++++++++++++++++++++++++- 3 files changed, 283 insertions(+), 48 deletions(-) diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 56ab8ae3da..826f069093 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -8929,52 +8929,37 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef VarList, SmallVector DstExprs; SmallVector AssignmentOps; for (auto &RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP copyprivate clause."); - if (isa(RefExpr)) { + assert(RefExpr && "NULL expr in OpenMP linear clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/false); + if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); SrcExprs.push_back(nullptr); DstExprs.push_back(nullptr); AssignmentOps.push_back(nullptr); - continue; } - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // OpenMP [2.14.4.1, Restrictions, p.1] - // A list item that appears in a copyin clause must be threadprivate. - DeclRefExpr *DE = dyn_cast(RefExpr); - if (!DE || !isa(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name_member_expr) - << 0 << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - - Decl *D = DE->getDecl(); - VarDecl *VD = cast(D); - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); - SrcExprs.push_back(nullptr); - DstExprs.push_back(nullptr); - AssignmentOps.push_back(nullptr); - continue; - } + QualType Type = D->getType(); + auto *VD = dyn_cast(D); // OpenMP [2.14.4.2, Restrictions, p.2] // A list item that appears in a copyprivate clause may not appear in a // private or firstprivate clause on the single construct. - if (!DSAStack->isThreadPrivate(VD)) { - auto DVar = DSAStack->getTopDSA(VD, false); + if (!VD || !DSAStack->isThreadPrivate(VD)) { + auto DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_copyprivate && DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_copyprivate); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -8982,12 +8967,12 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef VarList, // All list items that appear in a copyprivate clause must be either // threadprivate or private in the enclosing context. if (DVar.CKind == OMPC_unknown) { - DVar = DSAStack->getImplicitDSA(VD, false); + DVar = DSAStack->getImplicitDSA(D, false); if (DVar.CKind == OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_copyprivate) << "threadprivate or private in the enclosing context"; - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } } @@ -8999,10 +8984,11 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef VarList, << getOpenMPClauseName(OMPC_copyprivate) << Type << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); bool IsDecl = + !VD || VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; continue; } @@ -9013,27 +8999,29 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef VarList, Type = Context.getBaseElementType(Type.getNonReferenceType()) .getUnqualifiedType(); auto *SrcVD = - buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.src", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *PseudoSrcExpr = - buildDeclRefExpr(*this, SrcVD, Type, DE->getExprLoc()); + buildVarDecl(*this, RefExpr->getLocStart(), Type, ".copyprivate.src", + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *PseudoSrcExpr = buildDeclRefExpr(*this, SrcVD, Type, ELoc); auto *DstVD = - buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.dst", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); + buildVarDecl(*this, RefExpr->getLocStart(), Type, ".copyprivate.dst", + D->hasAttrs() ? &D->getAttrs() : nullptr); auto *PseudoDstExpr = - buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc()); - auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, + buildDeclRefExpr(*this, DstVD, Type, ELoc); + auto AssignmentOp = BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, PseudoDstExpr, PseudoSrcExpr); if (AssignmentOp.isInvalid()) continue; - AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), + AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), ELoc, /*DiscardedValue=*/true); if (AssignmentOp.isInvalid()) continue; // No need to mark vars as copyprivate, they are already threadprivate or // implicitly private. - Vars.push_back(DE); + assert(VD || IsOpenMPCapturedDecl(D)); + Vars.push_back( + VD ? RefExpr->IgnoreParens() + : buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false)); SrcExprs.push_back(PseudoSrcExpr); DstExprs.push_back(PseudoDstExpr); AssignmentOps.push_back(AssignmentOp.get()); diff --git a/test/OpenMP/single_ast_print.cpp b/test/OpenMP/single_ast_print.cpp index 8eb35174a7..d30b7feb02 100644 --- a/test/OpenMP/single_ast_print.cpp +++ b/test/OpenMP/single_ast_print.cpp @@ -8,15 +8,43 @@ void foo() {} +struct SS { + int a; + int b : 4; + int &c; + SS(int &d) : a(0), b(0), c(d) { +#pragma omp parallel firstprivate(a, b, c) +#pragma omp single copyprivate(a, this->b, (this)->c) +// CHECK: #pragma omp parallel firstprivate(this->a,this->b,this->c) +// CHECK-NEXT: #pragma omp single copyprivate(this->a,this->b,this->c) + ++this->a, --b, (this)->c /= 1; + } +}; + +template +struct SST { + T a; + SST() : a(T()) { +// CHECK: #pragma omp parallel firstprivate(this->a) +// CHECK-NEXT: #pragma omp single copyprivate(this->a) +// CHECK: #pragma omp parallel firstprivate(this->a) +// CHECK-NEXT: #pragma omp single copyprivate(this->a) +#pragma omp parallel firstprivate(a) +#pragma omp single copyprivate(this->a) + ++this->a; + } +}; + template T tmain(T argc) { T b = argc, c, d, e, f, g; static T a; + SST sst; // CHECK: static T a; #pragma omp parallel private(g) #pragma omp single private(argc, b), firstprivate(c, d), nowait foo(); - // CHECK-NEXT: #pragma omp parallel private(g) + // CHECK: #pragma omp parallel private(g) // CHECK-NEXT: #pragma omp single private(argc,b) firstprivate(c,d) nowait // CHECK-NEXT: foo(); #pragma omp parallel private(g) @@ -31,11 +59,12 @@ T tmain(T argc) { int main(int argc, char **argv) { int b = argc, c, d, e, f, g; static int a; + SS ss(a); // CHECK: static int a; #pragma omp parallel private(g) #pragma omp single private(argc, b), firstprivate(argv, c), nowait foo(); - // CHECK-NEXT: #pragma omp parallel private(g) + // CHECK: #pragma omp parallel private(g) // CHECK-NEXT: #pragma omp single private(argc,b) firstprivate(argv,c) nowait // CHECK-NEXT: foo(); #pragma omp parallel private(g) diff --git a/test/OpenMP/single_codegen.cpp b/test/OpenMP/single_codegen.cpp index 61a93a5a1b..58c5e82c16 100644 --- a/test/OpenMP/single_codegen.cpp +++ b/test/OpenMP/single_codegen.cpp @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -verify -fopenmp -fnoopenmp-use-tls -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -fnoopenmp-use-tls -x c++ -std=c++11 -triple x86_64-unknown-unknown -emit-llvm %s -fexceptions -fcxx-exceptions -o - | FileCheck %s // RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -x c++ -std=c++11 -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -fnoopenmp-use-tls -x c++ -triple x86_64-unknown-unknown -fexceptions -fcxx-exceptions -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -fopenmp -fnoopenmp-use-tls -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin10 -std=c++11 -fopenmp -fnoopenmp-use-tls -fexceptions -fcxx-exceptions -debug-info-kind=line-tables-only -x c++ -emit-llvm %s -o - | FileCheck %s --check-prefix=TERM_DEBUG // RUN: %clang_cc1 -verify -fopenmp -fnoopenmp-use-tls -x c++ -std=c++11 -DARRAY -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=ARRAY %s // expected-no-diagnostics // REQUIRES: x86-registered-target @@ -19,7 +19,9 @@ public: }; // CHECK-DAG: [[TEST_CLASS_TY:%.+]] = type { i{{[0-9]+}} } -// CHECK: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* } +// CHECK-DAG: [[SST_TY:%.+]] = type { double } +// CHECK-DAG: [[SS_TY:%.+]] = type { i32, i8, i32* } +// CHECK-DAG: [[IDENT_T_TY:%.+]] = type { i32, i32, i32, i32, i8* } // CHECK: [[IMPLICIT_BARRIER_SINGLE_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 322, i32 0, i32 0, i8* // CHECK: define void [[FOO:@.+]]() @@ -30,6 +32,39 @@ TestClass tc2[2]; void foo() {} +struct SS { + int a; + int b : 4; + int &c; + SS(int &d) : a(0), b(0), c(d) { +#pragma omp parallel firstprivate(a, b, c) +#pragma omp single copyprivate(a, this->b, (this)->c) + [&]() { + ++this->a, --b, (this)->c /= 1; +#pragma omp parallel firstprivate(a, b, c) +#pragma omp single copyprivate(a, this->b, (this)->c) + ++(this)->a, --b, this->c /= 1; + }(); + } +}; + +template +struct SST { + T a; + SST() : a(T()) { +#pragma omp parallel firstprivate(a) +#pragma omp single copyprivate(this->a) + [&]() { + [&]() { + ++this->a; +#pragma omp parallel firstprivate(a) +#pragma omp single copyprivate((this)->a) + ++(this)->a; + }(); + }(); + } +}; + // CHECK-LABEL: @main // TERM_DEBUG-LABEL: @main int main() { @@ -39,6 +74,8 @@ int main() { char a; char a2[2]; TestClass &c = tc; + SST sst; + SS ss(c.a); // CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num([[IDENT_T_TY]]* [[DEFAULT_LOC:@.+]]) // CHECK-DAG: [[DID_IT:%.+]] = alloca i32, @@ -186,3 +223,184 @@ void array_func(int n, int a[n], St s[2]) { // ARRAY: store i32* %{{.+}}, i32** %{{.+}}, // ARRAY: store %struct.St* %{{.+}}, %struct.St** %{{.+}}, #endif + +// CHECK-LABEL:@_ZN2SSC2ERi( +// CHECK: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* @{{.+}}, i32 4, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, [[SS_TY]]*, i32*, i32*, i32*)* [[SS_MICROTASK:@.+]] to void +// CHECK-NEXT: ret void + +// CHECK: define internal void [[SS_MICROTASK]](i32* {{[^,]+}}, i32* {{[^,]+}}, [[SS_TY]]* {{.+}}, i32* {{.+}}, i32* {{.+}}, i32* {{.+}}) +// Private a +// CHECK: alloca i32, +// CHECK: alloca i32*, +// Private b +// CHECK: alloca i32, +// Private c +// CHECK: alloca i32, +// CHECK: alloca i32*, +// CHECK: [[DID_IT:%.+]] = alloca i32, +// CHECK: store i32 0, i32* [[DID_IT]], +// CHECK: [[RES:%.+]] = call i32 @__kmpc_single([[IDENT_T_TY]]* @{{.+}}, i32 %{{.+}}) +// CHECK-NEXT: icmp ne i32 [[RES]], 0 +// CHECK-NEXT: br i1 + +// CHECK: getelementptr inbounds [[CAP_TY:%.+]], [[CAP_TY]]* [[CAP:%.+]], i32 0, i32 0 +// CHECK: getelementptr inbounds [[CAP_TY]], [[CAP_TY]]* [[CAP]], i32 0, i32 1 +// CHECK-NEXT: load i32*, i32** % +// CHECK-NEXT: store i32* % +// CHECK-NEXT: getelementptr inbounds [[CAP_TY]], [[CAP_TY]]* [[CAP]], i32 0, i32 2 +// CHECK-NEXT: store i32* % +// CHECK-NEXT: getelementptr inbounds [[CAP_TY]], [[CAP_TY]]* [[CAP]], i32 0, i32 3 +// CHECK-NEXT: load i32*, i32** % +// CHECK-NEXT: store i32* % +// CHECK-LABEL: invoke void @_ZZN2SSC1ERiENKUlvE_clEv( +// CHECK-SAME: [[CAP_TY]]* [[CAP]]) + +// CHECK: store i32 1, i32* [[DID_IT]], +// CHECK: call void @__kmpc_end_single([[IDENT_T_TY]]* @{{.+}}, i32 %{{.+}}) +// CHECK: br label + +// CHECK: call void @__kmpc_end_single(%{{.+}}* @{{.+}}, i32 %{{.+}}) +// CHECK: br label + +// CHECK: getelementptr inbounds [3 x i8*], [3 x i8*]* [[LIST:%.+]], i64 0, i64 0 +// CHECK: load i32*, i32** % +// CHECK-NEXT: bitcast i32* % +// CHECK-NEXT: store i8* % +// CHECK: getelementptr inbounds [3 x i8*], [3 x i8*]* [[LIST]], i64 0, i64 1 +// CHECK-NEXT: bitcast i32* % +// CHECK-NEXT: store i8* % +// CHECK: getelementptr inbounds [3 x i8*], [3 x i8*]* [[LIST]], i64 0, i64 2 +// CHECK: load i32*, i32** % +// CHECK-NEXT: bitcast i32* % +// CHECK-NEXT: store i8* % +// CHECK-NEXT: bitcast [3 x i8*]* [[LIST]] to i8* +// CHECK-NEXT: load i32, i32* [[DID_IT]], +// CHECK-NEXT: call void @__kmpc_copyprivate([[IDENT_T_TY]]* @{{.+}}, i32 %{{.+}}, i64 24, i8* %{{.+}}, void (i8*, i8*)* [[COPY_FUNC:@[^,]+]], i32 %{{.+}}) +// CHECK-NEXT: ret void + +// CHECK-LABEL: @_ZZN2SSC1ERiENKUlvE_clEv( +// CHECK: getelementptr inbounds [[CAP_TY]], [[CAP_TY]]* [[CAP:%.+]], i32 0, i32 1 +// CHECK-NEXT: load i32*, i32** % +// CHECK-NEXT: load i32, i32* % +// CHECK-NEXT: add nsw i32 %{{.+}}, 1 +// CHECK-NEXT: store i32 % +// CHECK-NEXT: getelementptr inbounds [[CAP_TY]], [[CAP_TY]]* [[CAP]], i32 0, i32 2 +// CHECK-NEXT: load i32*, i32** % +// CHECK-NEXT: load i32, i32* % +// CHECK-NEXT: add nsw i32 %{{.+}}, -1 +// CHECK-NEXT: store i32 % +// CHECK-NEXT: getelementptr inbounds [[CAP_TY]], [[CAP_TY]]* [[CAP]], i32 0, i32 3 +// CHECK-NEXT: load i32*, i32** % +// CHECK-NEXT: load i32, i32* % +// CHECK-NEXT: sdiv i32 %{{.+}}, 1 +// CHECK-NEXT: store i32 % +// CHECK-NEXT: getelementptr inbounds [[CAP_TY]], [[CAP_TY]]* [[CAP]], i32 0, i32 1 +// CHECK-NEXT: load i32*, i32** % +// CHECK-NEXT: getelementptr inbounds [[CAP_TY]], [[CAP_TY]]* [[CAP]], i32 0, i32 2 +// CHECK-NEXT: load i32*, i32** % +// CHECK-NEXT: getelementptr inbounds [[CAP_TY]], [[CAP_TY]]* [[CAP]], i32 0, i32 3 +// CHECK-NEXT: load i32*, i32** % +// CHECK-NEXT: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* @{{.+}}, i32 4, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, [[SS_TY]]*, i32*, i32*, i32*)* [[SS_MICROTASK1:@.+]] to void +// CHECK-NEXT: ret void + +// CHECK: define internal void [[COPY_FUNC]](i8*, i8*) +// CHECK: ret void + +// CHECK: define internal void [[SS_MICROTASK1]](i32* {{[^,]+}}, i32* {{[^,]+}}, [[SS_TY]]* {{.+}}, i32* {{.+}}, i32* {{.+}}, i32* {{.+}}) +// Private a +// CHECK: alloca i32, +// CHECK: alloca i32*, +// Private b +// CHECK: alloca i32, +// Private c +// CHECK: alloca i32, +// CHECK: alloca i32*, +// CHECK: [[DID_IT:%.+]] = alloca i32, +// CHECK: [[RES:%.+]] = call i32 @__kmpc_single([[IDENT_T_TY]]* @{{.+}}, i32 %{{.+}}) +// CHECK-NEXT: icmp ne i32 [[RES]], 0 +// CHECK-NEXT: br i1 + +// CHECK-NOT: getelementptr inbounds +// CHECK: load i32*, i32** % +// CHECK-NEXT: load i32, i32* % +// CHECK-NEXT: add nsw i32 %{{.+}}, 1 +// CHECK-NEXT: store i32 % +// CHECK-NOT: getelementptr inbounds +// CHECK: load i32, i32* % +// CHECK-NEXT: add nsw i32 %{{.+}}, -1 +// CHECK-NEXT: store i32 % +// CHECK-NOT: getelementptr inbounds +// CHECK: load i32*, i32** % +// CHECK-NEXT: load i32, i32* % +// CHECK-NEXT: sdiv i32 %{{.+}}, 1 +// CHECK-NEXT: store i32 % +// CHECK-NEXT: store i32 1, i32* [[DID_IT]], +// CHECK-NEXT: call void @__kmpc_end_single([[IDENT_T_TY]]* @{{.+}}, i32 %{{.+}}) +// CHECK-NEXT: br label + +// CHECK: getelementptr inbounds [3 x i8*], [3 x i8*]* [[LIST:%.+]], i64 0, i64 0 +// CHECK: load i32*, i32** % +// CHECK-NEXT: bitcast i32* % +// CHECK-NEXT: store i8* % +// CHECK: getelementptr inbounds [3 x i8*], [3 x i8*]* [[LIST]], i64 0, i64 1 +// CHECK-NEXT: bitcast i32* % +// CHECK-NEXT: store i8* % +// CHECK: getelementptr inbounds [3 x i8*], [3 x i8*]* [[LIST]], i64 0, i64 2 +// CHECK: load i32*, i32** % +// CHECK-NEXT: bitcast i32* % +// CHECK-NEXT: store i8* % +// CHECK-NEXT: bitcast [3 x i8*]* [[LIST]] to i8* +// CHECK-NEXT: load i32, i32* [[DID_IT]], +// CHECK-NEXT: call void @__kmpc_copyprivate([[IDENT_T_TY]]* @{{.+}}, i32 %{{.+}}, i64 24, i8* %{{.+}}, void (i8*, i8*)* [[COPY_FUNC:@[^,]+]], i32 %{{.+}}) +// CHECK-NEXT: ret void + +// CHECK: define internal void [[COPY_FUNC]](i8*, i8*) +// CHECK: ret void + +// CHECK-LABEL: @_ZN3SSTIdEC2Ev +// CHECK: getelementptr inbounds [[SST_TY]], [[SST_TY]]* %{{.+}}, i32 0, i32 0 +// CHECK-NEXT: store double 0.000000e+00, double* % +// CHECK-NEXT: getelementptr inbounds [[SST_TY]], [[SST_TY]]* %{{.+}}, i32 0, i32 0 +// CHECK-NEXT: store double* % +// CHECK-NEXT: load double*, double** % +// CHECK-NEXT: call void ([[IDENT_T_TY]]*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call([[IDENT_T_TY]]* @{{.+}}, i32 2, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, [[SST_TY]]*, double*)* [[SST_MICROTASK:@.+]] to void +// CHECK-NEXT: ret void + +// CHECK: define internal void [[SST_MICROTASK]](i32* {{[^,]+}}, i32* {{[^,]+}}, [[SST_TY]]* {{.+}}, double* {{.+}}) +// CHECK: [[RES:%.+]] = call i32 @__kmpc_single([[IDENT_T_TY]]* @{{.+}}, i32 %{{.+}}) +// CHECK-NEXT: icmp ne i32 [[RES]], 0 +// CHECK-NEXT: br i1 + +// CHECK: getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i32 0, i32 1 +// CHECK-NEXT: load double*, double** % +// CHECK-NEXT: store double* % +// CHECK-LABEL: invoke void @_ZZN3SSTIdEC1EvENKUlvE_clEv( + +// CHECK: store i32 1, i32* [[DID_IT]], +// CHECK-NEXT: call void @__kmpc_end_single([[IDENT_T_TY]]* @{{.+}}, i32 %{{.+}}) +// CHECK-NEXT: br label + +// CHECK: call void @__kmpc_end_single([[IDENT_T_TY]]* @{{.+}}, i32 %{{.+}}) +// CHECK-NEXT: br label + +// CHECK: getelementptr inbounds [1 x i8*], [1 x i8*]* [[LIST:%.+]], i64 0, i64 0 +// CHECK: load double*, double** % +// CHECK-NEXT: bitcast double* % +// CHECK-NEXT: store i8* % +// CHECK-NEXT: bitcast [1 x i8*]* [[LIST]] to i8* +// CHECK-NEXT: load i32, i32* [[DID_IT]], +// CHECK-NEXT: call void @__kmpc_copyprivate([[IDENT_T_TY]]* @{{.+}}, i32 %{{.+}}, i64 8, i8* %{{.+}}, void (i8*, i8*)* [[COPY_FUNC:@[^,]+]], i32 %{{.+}}) +// CHECK-NEXT: ret void + +// CHECK-LABEL: @_ZZN3SSTIdEC1EvENKUlvE_clEv( +// CHECK: getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i32 0, i32 1 +// CHECK-NEXT: getelementptr inbounds %{{.+}}, %{{.+}}* %{{.+}}, i32 0, i32 1 +// CHECK-NEXT: load double*, double** % +// CHECK-NEXT: store double* % +// CHECK-LABEL: call void @_ZZZN3SSTIdEC1EvENKUlvE_clEvENKUlvE_clEv( +// CHECK-NEXT: ret void + +// CHECK: define internal void [[COPY_FUNC]](i8*, i8*) +// CHECK: ret void + +// CHECK-LABEL: @_ZZZN3SSTIdEC1EvENKUlvE_clEvENKUlvE_clEv( -- 2.40.0