Hi doug.gregor, hfinkel, rjmccall, rsmith, fraggamuffin, ejstotzer,
This patch generates some helper variables which used as a private copies of
the corresponding original variables inside an OpenMP 'parallel' directive.
These generated variables are initialized by default (with the default
constructor, if any). In outlined function references to original variables are
replaced by the references to these private helper variables. At the end of the
initialization of the private variables and implicit barier is set by calling
__kmpc_barrier(...) runtime function to be sure that all threads were
initialized using original values of the variables.
http://reviews.llvm.org/D4752
Files:
include/clang/AST/DataRecursiveASTVisitor.h
include/clang/AST/OpenMPClause.h
include/clang/AST/RecursiveASTVisitor.h
lib/AST/Stmt.cpp
lib/AST/StmtProfile.cpp
lib/CodeGen/CGOpenMPRuntime.cpp
lib/CodeGen/CGOpenMPRuntime.h
lib/CodeGen/CGStmtOpenMP.cpp
lib/CodeGen/CodeGenFunction.h
lib/Sema/SemaOpenMP.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
test/OpenMP/for_private_messages.cpp
test/OpenMP/parallel_codegen.cpp
test/OpenMP/parallel_for_private_messages.cpp
test/OpenMP/parallel_private_codegen.cpp
test/OpenMP/parallel_private_messages.cpp
test/OpenMP/parallel_sections_private_messages.cpp
test/OpenMP/sections_private_messages.cpp
test/OpenMP/simd_private_messages.cpp
test/OpenMP/single_private_messages.cpp
test/OpenMP/task_private_messages.cpp
tools/libclang/CIndex.cpp
Index: test/OpenMP/single_private_messages.cpp
===================================================================
--- test/OpenMP/single_private_messages.cpp
+++ test/OpenMP/single_private_messages.cpp
@@ -24,16 +24,16 @@
S3() : a(0) {}
};
const S3 ca[5];
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -92,8 +92,8 @@
}
int main(int argc, char **argv) {
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp single private // expected-error {{expected '(' after 'private'}}
@@ -116,7 +116,7 @@
foo();
#pragma omp single private(argv[1]) // expected-error {{expected variable name}}
foo();
-#pragma omp single private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+#pragma omp single private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
foo();
#pragma omp single private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
foo();
Index: test/OpenMP/parallel_codegen.cpp
===================================================================
--- test/OpenMP/parallel_codegen.cpp
+++ test/OpenMP/parallel_codegen.cpp
@@ -39,7 +39,7 @@
// CHECK: [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon* [[AGG_CAPTURED]], i32 0, i32 0
// CHECK-NEXT: store i32* {{%[a-z0-9.]+}}, i32** [[ARGC_REF]]
// CHECK-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8*
-// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @__captured_stmt to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @.omp_outlined. to void (i32*, i32*, ...)*), i8* [[BITCAST]])
// CHECK-NEXT: [[ARGV:%.+]] = load i8*** {{%[a-z0-9.]+}}
// CHECK-NEXT: [[RET:%.+]] = call {{[a-z]*[ ]?i32}} [[TMAIN:@.+tmain.+]](i8** [[ARGV]])
// CHECK-NEXT: ret i32 [[RET]]
@@ -55,13 +55,13 @@
// CHECK-DEBUG-NEXT: [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t* [[LOC_2_ADDR]], i32 0, i32 4
// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.+}} x i8]* [[LOC1]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]]
// CHECK-DEBUG-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon* [[AGG_CAPTURED]] to i8*
-// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @__captured_stmt to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon*)* @.omp_outlined. to void (i32*, i32*, ...)*), i8* [[BITCAST]])
// CHECK-DEBUG-NEXT: [[ARGV:%.+]] = load i8*** {{%[a-z0-9.]+}}
// CHECK-DEBUG-NEXT: [[RET:%.+]] = call i32 [[TMAIN:@.+tmain.+]](i8** [[ARGV]])
// CHECK-DEBUG-NEXT: ret i32 [[RET]]
// CHECK-DEBUG-NEXT: }
-// CHECK-LABEL: define internal void @__captured_stmt(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
+// CHECK-LABEL: define internal void @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
// CHECK: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon*
// CHECK: store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]]
// CHECK: [[CONTEXT_PTR:%.+]] = load %struct.anon** [[CONTEXT_ADDR]]
@@ -73,7 +73,7 @@
// CHECK: call void @{{.+terminate.*}}(
// CHECK-NEXT: unreachable
// CHECK-NEXT: }
-// CHECK-DEBUG-LABEL: define internal void @__captured_stmt(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
+// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.(i32* %.global_tid., i32* %.bound_tid., %struct.anon* %__context)
// CHECK-DEBUG: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon*
// CHECK-DEBUG: store %struct.anon* %__context, %struct.anon** [[CONTEXT_ADDR]]
// CHECK-DEBUG: [[CONTEXT_PTR:%.+]] = load %struct.anon** [[CONTEXT_ADDR]]
@@ -96,7 +96,7 @@
// CHECK: [[ARGC_REF:%.+]] = getelementptr inbounds %struct.anon.0* [[AGG_CAPTURED]], i32 0, i32 0
// CHECK-NEXT: store i8*** {{%[a-z0-9.]+}}, i8**** [[ARGC_REF]]
// CHECK-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8*
-// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @__captured_stmt1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[DEF_LOC_2]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @.omp_outlined.1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
// CHECK-NEXT: ret i32 0
// CHECK-NEXT: }
// CHECK-DEBUG: define linkonce_odr i32 [[TMAIN]](i8** %argc)
@@ -110,11 +110,11 @@
// CHECK-DEBUG-NEXT: [[KMPC_LOC_PSOURCE_REF:%.+]] = getelementptr inbounds %ident_t* [[LOC_2_ADDR]], i32 0, i32 4
// CHECK-DEBUG-NEXT: store i8* getelementptr inbounds ([{{.+}} x i8]* [[LOC2]], i32 0, i32 0), i8** [[KMPC_LOC_PSOURCE_REF]]
// CHECK-DEBUG-NEXT: [[BITCAST:%.+]] = bitcast %struct.anon.0* [[AGG_CAPTURED]] to i8*
-// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @__captured_stmt1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
+// CHECK-DEBUG-NEXT: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...)* @__kmpc_fork_call(%ident_t* [[LOC_2_ADDR]], i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, %struct.anon.0*)* @.omp_outlined.1 to void (i32*, i32*, ...)*), i8* [[BITCAST]])
// CHECK-DEBUG-NEXT: ret i32 0
// CHECK-DEBUG-NEXT: }
-// CHECK-LABEL: define internal void @__captured_stmt1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
+// CHECK-LABEL: define internal void @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
// CHECK: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0*
// CHECK: store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]]
// CHECK: [[CONTEXT_PTR:%.+]] = load %struct.anon.0** [[CONTEXT_ADDR]]
@@ -126,7 +126,7 @@
// CHECK: call void @{{.+terminate.*}}(
// CHECK-NEXT: unreachable
// CHECK-NEXT: }
-// CHECK-DEBUG-LABEL: define internal void @__captured_stmt1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
+// CHECK-DEBUG-LABEL: define internal void @.omp_outlined.1(i32* %.global_tid., i32* %.bound_tid., %struct.anon.0* %__context)
// CHECK-DEBUG: [[CONTEXT_ADDR:%.+]] = alloca %struct.anon.0*
// CHECK-DEBUG: store %struct.anon.0* %__context, %struct.anon.0** [[CONTEXT_ADDR]]
// CHECK-DEBUG: [[CONTEXT_PTR:%.+]] = load %struct.anon.0** [[CONTEXT_ADDR]]
Index: test/OpenMP/task_private_messages.cpp
===================================================================
--- test/OpenMP/task_private_messages.cpp
+++ test/OpenMP/task_private_messages.cpp
@@ -27,16 +27,16 @@
const S3 c; // expected-note {{global variable is predetermined as shared}}
const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
extern const int f; // expected-note {{global variable is predetermined as shared}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -48,8 +48,8 @@
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = {0}; // expected-note {{constant variable is predetermined as shared}}
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp task private // expected-error {{expected '(' after 'private'}}
@@ -66,7 +66,7 @@
#pragma omp task private(ca) // expected-error {{shared variable cannot be private}}
#pragma omp task private(da) // expected-error {{shared variable cannot be private}}
#pragma omp task private(S2::S2s) // expected-error {{shared variable cannot be private}}
-#pragma omp task private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+#pragma omp task private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
#pragma omp task private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}}
#pragma omp task shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}}
foo();
Index: test/OpenMP/simd_private_messages.cpp
===================================================================
--- test/OpenMP/simd_private_messages.cpp
+++ test/OpenMP/simd_private_messages.cpp
@@ -22,15 +22,15 @@
S3():a(0) { }
};
const S3 ca[5];
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v):a(v) { }
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5():a(0) {}
+ S5():a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v):a(v) { }
};
@@ -86,8 +86,8 @@
}
int main(int argc, char **argv) {
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp simd private // expected-error {{expected '(' after 'private'}}
@@ -110,7 +110,7 @@
for (int k = 0; k < argc; ++k) ++k;
#pragma omp simd private (argv[1]) // expected-error {{expected variable name}}
for (int k = 0; k < argc; ++k) ++k;
- #pragma omp simd private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+ #pragma omp simd private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (int k = 0; k < argc; ++k) ++k;
#pragma omp simd private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
for (int k = 0; k < argc; ++k) ++k;
Index: test/OpenMP/parallel_private_codegen.cpp
===================================================================
--- test/OpenMP/parallel_private_codegen.cpp
+++ test/OpenMP/parallel_private_codegen.cpp
@@ -0,0 +1,105 @@
+// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -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
+// expected-no-diagnostics
+#ifndef HEADER
+#define HEADER
+
+template <class T>
+struct S {
+ T f;
+ S(T a) : f(a) {}
+ S() : f() {}
+ operator T() { return T(); }
+ ~S() {}
+};
+
+// 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]+}} }
+// CHECK: [[CAP_TMAIN_TY:%.+]] = type { [2 x i{{[0-9]+}}]*, i{{[0-9]+}}*, [2 x [[S_INT_TY]]]*, [[S_INT_TY]]* }
+// CHECK: [[IMPLICIT_BARRIER_LOC:@.+]] = private unnamed_addr constant %{{.+}} { i32 0, i32 66, i32 0, i32 0, i8*
+template <typename T>
+T tmain() {
+ S<T> test;
+ T t_var;
+ T vec[] = {1, 2};
+ S<T> s_arr[] = {1, 2};
+ S<T> var(3);
+#pragma omp parallel private(t_var, vec, s_arr, var)
+ {
+ vec[0] = t_var;
+ s_arr[0] = var;
+ }
+ return T();
+}
+
+int main() {
+ S<float> test;
+ int t_var;
+ int vec[] = {1, 2};
+ S<float> s_arr[] = {1, 2};
+ S<float> var(3);
+#pragma omp parallel private(t_var, vec, s_arr, var)
+ {
+ vec[0] = t_var;
+ s_arr[0] = var;
+ }
+ return tmain<int>();
+}
+
+// CHECK: define i{{[0-9]+}} @main()
+// CHECK: [[TEST:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: call void [[S_FLOAT_TY_DEF_CONSTR:@.+]]([[S_FLOAT_TY]]* [[TEST]])
+// CHECK: %{{.+}} = bitcast [[CAP_MAIN_TY]]*
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_MAIN_TY]]*)* [[MAIN_MICROTASK:@.+]] to void
+// CHECK: = call i{{.+}} [[TMAIN_INT:@.+]]()
+// CHECK: call void [[S_FLOAT_TY_DESTR:@.+]]([[S_FLOAT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[MAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_MAIN_TY]]* %{{.+}})
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_FLOAT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_FLOAT_TY]],
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_ADDR]]
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_FLOAT_TY]]*
+// CHECK: call void [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[S_ARR_PRIV_ITEM]])
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: call void [[S_FLOAT_TY_DEF_CONSTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call void [[S_FLOAT_TY_DESTR]]([[S_FLOAT_TY]]*
+// CHECK: ret void
+
+// CHECK: define {{.*}} i{{[0-9]+}} [[TMAIN_INT]]()
+// CHECK: [[TEST:%.+]] = alloca [[S_INT_TY]],
+// CHECK: call void [[S_INT_TY_DEF_CONSTR:@.+]]([[S_INT_TY]]* [[TEST]])
+// CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...)* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[CAP_TMAIN_TY]]*)* [[TMAIN_MICROTASK:@.+]] to void
+// CHECK: call void [[S_INT_TY_DESTR:@.+]]([[S_INT_TY]]*
+// CHECK: ret
+//
+// CHECK: define internal void [[TMAIN_MICROTASK]](i{{[0-9]+}}* [[GTID_ADDR:%.+]], i{{[0-9]+}}* %{{.+}}, [[CAP_TMAIN_TY]]* %{{.+}})
+// CHECK: [[T_VAR_PRIV:%.+]] = alloca i{{[0-9]+}},
+// CHECK: [[VEC_PRIV:%.+]] = alloca [2 x i{{[0-9]+}}],
+// CHECK: [[S_ARR_PRIV:%.+]] = alloca [2 x [[S_INT_TY]]],
+// CHECK: [[VAR_PRIV:%.+]] = alloca [[S_INT_TY]],
+// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_ADDR]]
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: {{.+}}:
+// CHECK: [[S_ARR_PRIV_ITEM:%.+]] = phi [[S_INT_TY]]*
+// CHECK: call void [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[S_ARR_PRIV_ITEM]])
+// CHECK-NOT: [[T_VAR_PRIV]]
+// CHECK-NOT: [[VEC_PRIV]]
+// CHECK: call void [[S_INT_TY_DEF_CONSTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+// CHECK: call void @__kmpc_barrier(%{{.+}}* [[IMPLICIT_BARRIER_LOC]], i{{[0-9]+}} [[GTID]])
+// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]* [[VAR_PRIV]])
+// CHECK-DAG: call void [[S_INT_TY_DESTR]]([[S_INT_TY]]*
+// CHECK: ret void
+#endif
+
Index: test/OpenMP/parallel_for_private_messages.cpp
===================================================================
--- test/OpenMP/parallel_for_private_messages.cpp
+++ test/OpenMP/parallel_for_private_messages.cpp
@@ -24,16 +24,16 @@
S3() : a(0) {}
};
const S3 ca[5];
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -109,8 +109,8 @@
}
int main(int argc, char **argv) {
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel for private // expected-error {{expected '(' after 'private'}}
@@ -143,7 +143,7 @@
#pragma omp parallel for private(argv[1]) // expected-error {{expected variable name}}
for (int k = 0; k < argc; ++k)
++k;
-#pragma omp parallel for private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+#pragma omp parallel for private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp parallel for private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
Index: test/OpenMP/parallel_sections_private_messages.cpp
===================================================================
--- test/OpenMP/parallel_sections_private_messages.cpp
+++ test/OpenMP/parallel_sections_private_messages.cpp
@@ -24,16 +24,16 @@
S3() : a(0) {}
};
const S3 ca[5];
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -124,8 +124,8 @@
}
int main(int argc, char **argv) {
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel sections private // expected-error {{expected '(' after 'private'}}
@@ -168,7 +168,7 @@
{
foo();
}
-#pragma omp parallel sections private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+#pragma omp parallel sections private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
Index: test/OpenMP/for_private_messages.cpp
===================================================================
--- test/OpenMP/for_private_messages.cpp
+++ test/OpenMP/for_private_messages.cpp
@@ -24,16 +24,16 @@
S3() : a(0) {}
};
const S3 ca[5];
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -109,8 +109,8 @@
}
int main(int argc, char **argv) {
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp for private // expected-error {{expected '(' after 'private'}}
@@ -143,7 +143,7 @@
#pragma omp for private(argv[1]) // expected-error {{expected variable name}}
for (int k = 0; k < argc; ++k)
++k;
-#pragma omp for private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+#pragma omp for private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
for (int k = 0; k < argc; ++k)
++k;
#pragma omp for private(h) // expected-error {{threadprivate or thread local variable cannot be private}}
Index: test/OpenMP/sections_private_messages.cpp
===================================================================
--- test/OpenMP/sections_private_messages.cpp
+++ test/OpenMP/sections_private_messages.cpp
@@ -24,16 +24,16 @@
S3() : a(0) {}
};
const S3 ca[5];
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v) : a(v) {}
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5() : a(0) {}
+ S5() : a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v) : a(v) {}
@@ -124,8 +124,8 @@
}
int main(int argc, char **argv) {
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g(5);
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp sections private // expected-error {{expected '(' after 'private'}}
@@ -168,7 +168,7 @@
{
foo();
}
-#pragma omp sections private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+#pragma omp sections private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
{
foo();
}
Index: test/OpenMP/parallel_private_messages.cpp
===================================================================
--- test/OpenMP/parallel_private_messages.cpp
+++ test/OpenMP/parallel_private_messages.cpp
@@ -25,15 +25,15 @@
const S3 c; // expected-note {{global variable is predetermined as shared}}
const S3 ca[5]; // expected-note {{global variable is predetermined as shared}}
extern const int f; // expected-note {{global variable is predetermined as shared}}
-class S4 { // expected-note {{'S4' declared here}}
+class S4 {
int a;
- S4();
+ S4(); // expected-note {{implicitly declared private here}}
public:
S4(int v):a(v) { }
};
-class S5 { // expected-note {{'S5' declared here}}
+class S5 {
int a;
- S5():a(0) {}
+ S5():a(0) {} // expected-note {{implicitly declared private here}}
public:
S5(int v):a(v) { }
};
@@ -44,8 +44,8 @@
int main(int argc, char **argv) {
const int d = 5; // expected-note {{constant variable is predetermined as shared}}
const int da[5] = { 0 }; // expected-note {{constant variable is predetermined as shared}}
- S4 e(4); // expected-note {{'e' defined here}}
- S5 g(5); // expected-note {{'g' defined here}}
+ S4 e(4);
+ S5 g[] = {5, 6};
int i;
int &j = i; // expected-note {{'j' defined here}}
#pragma omp parallel private // expected-error {{expected '(' after 'private'}}
@@ -62,7 +62,7 @@
#pragma omp parallel private(ca) // expected-error {{shared variable cannot be private}}
#pragma omp parallel private(da) // expected-error {{shared variable cannot be private}}
#pragma omp parallel private(S2::S2s) // expected-error {{shared variable cannot be private}}
- #pragma omp parallel private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}}
+ #pragma omp parallel private(e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{calling a private constructor of class 'S5'}}
#pragma omp parallel private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}}
#pragma omp parallel shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}}
foo();
Index: include/clang/AST/DataRecursiveASTVisitor.h
===================================================================
--- include/clang/AST/DataRecursiveASTVisitor.h
+++ include/clang/AST/DataRecursiveASTVisitor.h
@@ -2457,6 +2457,9 @@
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) {
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->private_copies()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -2479,6 +2479,9 @@
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) {
TRY_TO(VisitOMPClauseList(C));
+ for (auto *E : C->private_copies()) {
+ TRY_TO(TraverseStmt(E));
+ }
return true;
}
Index: include/clang/AST/OpenMPClause.h
===================================================================
--- include/clang/AST/OpenMPClause.h
+++ include/clang/AST/OpenMPClause.h
@@ -138,7 +138,7 @@
return ArrayRef<const Expr *>(
reinterpret_cast<const Expr *const *>(
reinterpret_cast<const char *>(this) +
- llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf<Expr *>())),
+ llvm::RoundUpToAlignment(sizeof(T), llvm::alignOf<const Expr *>())),
NumVars);
}
};
@@ -926,6 +926,7 @@
/// with the variables 'a' and 'b'.
///
class OMPPrivateClause : public OMPVarListClause<OMPPrivateClause> {
+ friend class OMPClauseReader;
/// \brief Build clause with number of variables \a N.
///
/// \param StartLoc Starting location of the clause.
@@ -947,25 +948,56 @@
SourceLocation(), SourceLocation(),
N) {}
+ /// \brief Sets the list of references to private copies with initializers for
+ /// new private variables.
+ /// \param InitVL List of references.
+ void setPrivateCopies(ArrayRef<Expr *> VL);
+
+ /// \brief Gets the list of references to private copies with initializers for
+ /// new private variables.
+ MutableArrayRef<Expr *> getPrivateCopies() {
+ return MutableArrayRef<Expr *>(varlist_end(), varlist_size());
+ }
+ ArrayRef<const Expr *> getPrivateCopies() const {
+ return llvm::makeArrayRef(varlist_end(), varlist_size());
+ }
+
public:
/// \brief Creates clause with a list of variables \a VL.
///
/// \param C AST context.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param VL List of references to the variables.
+ /// \param PrivateVL List of references to private copies with initializers.
///
static OMPPrivateClause *Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation LParenLoc,
- SourceLocation EndLoc, ArrayRef<Expr *> VL);
+ SourceLocation EndLoc, ArrayRef<Expr *> VL,
+ ArrayRef<Expr *> PrivateVL);
/// \brief Creates an empty clause with the place for \a N variables.
///
/// \param C AST context.
/// \param N The number of variables.
///
static OMPPrivateClause *CreateEmpty(const ASTContext &C, unsigned N);
+ typedef MutableArrayRef<Expr *>::iterator private_copies_iterator;
+ typedef ArrayRef<const Expr *>::iterator private_copies_const_iterator;
+ typedef llvm::iterator_range<private_copies_iterator> private_copies_range;
+ typedef llvm::iterator_range<private_copies_const_iterator>
+ private_copies_const_range;
+
+ private_copies_range private_copies() {
+ return private_copies_range(getPrivateCopies().begin(),
+ getPrivateCopies().end());
+ }
+ private_copies_const_range private_copies() const {
+ return private_copies_const_range(getPrivateCopies().begin(),
+ getPrivateCopies().end());
+ }
+
StmtRange children() {
return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()),
reinterpret_cast<Stmt **>(varlist_end()));
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -1993,12 +1993,16 @@
template<typename T>
void OMPClauseEnqueue::VisitOMPClauseList(T *Node) {
- for (const auto *I : Node->varlists())
+ for (const auto *I : Node->varlists()) {
Visitor->AddStmt(I);
+ }
}
void OMPClauseEnqueue::VisitOMPPrivateClause(const OMPPrivateClause *C) {
VisitOMPClauseList(C);
+ for (const auto *E : C->private_copies()) {
+ Visitor->AddStmt(E);
+ }
}
void OMPClauseEnqueue::VisitOMPFirstprivateClause(
const OMPFirstprivateClause *C) {
Index: lib/Sema/SemaOpenMP.cpp
===================================================================
--- lib/Sema/SemaOpenMP.cpp
+++ lib/Sema/SemaOpenMP.cpp
@@ -3059,11 +3059,13 @@
SourceLocation LParenLoc,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
+ SmallVector<Expr *, 8> PrivateCopies;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP private clause.");
if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
+ PrivateCopies.push_back(nullptr);
continue;
}
@@ -3085,6 +3087,7 @@
if (Type->isDependentType() || Type->isInstantiationDependentType()) {
// It will be analyzed later.
Vars.push_back(DE);
+ PrivateCopies.push_back(nullptr);
continue;
}
@@ -3110,54 +3113,8 @@
// A variable of class type (or array thereof) that appears in a private
// clause requires an accessible, unambiguous default constructor for the
// class type.
- while (Type.getNonReferenceType()->isArrayType()) {
- Type = cast<ArrayType>(Type.getNonReferenceType().getTypePtr())
- ->getElementType();
- }
- CXXRecordDecl *RD = getLangOpts().CPlusPlus
- ? Type.getNonReferenceType()->getAsCXXRecordDecl()
- : nullptr;
- // FIXME This code must be replaced by actual constructing/destructing of
- // the private variable.
- if (RD) {
- CXXConstructorDecl *CD = LookupDefaultConstructor(RD);
- PartialDiagnostic PD =
- PartialDiagnostic(PartialDiagnostic::NullDiagnostic());
- if (!CD ||
- CheckConstructorAccess(ELoc, CD,
- InitializedEntity::InitializeTemporary(Type),
- CD->getAccess(), PD) == AR_inaccessible ||
- CD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_private) << 0;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- Diag(RD->getLocation(), diag::note_previous_decl) << RD;
- continue;
- }
- MarkFunctionReferenced(ELoc, CD);
- DiagnoseUseOfDecl(CD, ELoc);
-
- CXXDestructorDecl *DD = RD->getDestructor();
- if (DD) {
- if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible ||
- DD->isDeleted()) {
- Diag(ELoc, diag::err_omp_required_method)
- << getOpenMPClauseName(OMPC_private) << 4;
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- Diag(RD->getLocation(), diag::note_previous_decl) << RD;
- continue;
- }
- MarkFunctionReferenced(ELoc, DD);
- DiagnoseUseOfDecl(DD, ELoc);
- }
+ while (Type->isArrayType()) {
+ Type = cast<ArrayType>(Type.getTypePtr())->getElementType();
}
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
@@ -3175,14 +3132,30 @@
continue;
}
+ auto VDPrivate =
+ VarDecl::Create(Context, CurContext, DE->getLocStart(),
+ DE->getExprLoc(), VD->getIdentifier(), VD->getType(),
+ VD->getTypeSourceInfo(), /*S*/ SC_Auto);
+ ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto*/ false);
+ if (VD->isInvalidDecl())
+ continue;
+ CurContext->addDecl(VDPrivate);
+ auto VDPrivateRefExpr = DeclRefExpr::Create(
+ Context, /*QualifierLoc*/ NestedNameSpecifierLoc(),
+ /*TemplateKWLoc*/ SourceLocation(), VDPrivate,
+ /*isEnclosingLocal*/ false, /*NameLoc*/ SourceLocation(), VD->getType(),
+ /*VK*/ VK_LValue);
+
DSAStack->addDSA(VD, DE, OMPC_private);
Vars.push_back(DE);
+ PrivateCopies.push_back(VDPrivateRefExpr);
}
if (Vars.empty())
return nullptr;
- return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
+ return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars,
+ PrivateCopies);
}
OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
Index: lib/AST/Stmt.cpp
===================================================================
--- lib/AST/Stmt.cpp
+++ lib/AST/Stmt.cpp
@@ -1122,25 +1122,32 @@
llvm_unreachable("unknown OMPClause");
}
-OMPPrivateClause *OMPPrivateClause::Create(const ASTContext &C,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc,
- ArrayRef<Expr *> VL) {
+void OMPPrivateClause::setPrivateCopies(ArrayRef<Expr *> VL) {
+ assert(VL.size() == varlist_size() &&
+ "Number of private copies is not the same as the preallocated buffer");
+ std::copy(VL.begin(), VL.end(), varlist_end());
+}
+
+OMPPrivateClause *
+OMPPrivateClause::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc,
+ ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL) {
+ // Allocate space for private variables and initializer expressions.
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * VL.size());
- OMPPrivateClause *Clause = new (Mem) OMPPrivateClause(StartLoc, LParenLoc,
- EndLoc, VL.size());
+ 2 * sizeof(Expr *) * VL.size());
+ OMPPrivateClause *Clause =
+ new (Mem) OMPPrivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
Clause->setVarRefs(VL);
+ Clause->setPrivateCopies(PrivateVL);
return Clause;
}
OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C,
unsigned N) {
void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause),
llvm::alignOf<Expr *>()) +
- sizeof(Expr *) * N);
+ 2 * sizeof(Expr *) * N);
return new (Mem) OMPPrivateClause(N);
}
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -322,12 +322,16 @@
template<typename T>
void OMPClauseProfiler::VisitOMPClauseList(T *Node) {
- for (auto *I : Node->varlists())
- Profiler->VisitStmt(I);
+ for (auto *E : Node->varlists()) {
+ Profiler->VisitStmt(E);
+ }
}
void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) {
VisitOMPClauseList(C);
+ for (auto *E : C->private_copies()) {
+ Profiler->VisitStmt(E);
+ }
}
void OMPClauseProfiler::VisitOMPFirstprivateClause(
const OMPFirstprivateClause *C) {
Index: lib/CodeGen/CGOpenMPRuntime.cpp
===================================================================
--- lib/CodeGen/CGOpenMPRuntime.cpp
+++ lib/CodeGen/CGOpenMPRuntime.cpp
@@ -50,18 +50,18 @@
DefaultOpenMPPSource =
llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy);
}
- llvm::GlobalVariable *DefaultOpenMPLocation = cast<llvm::GlobalVariable>(
- CGM.CreateRuntimeVariable(IdentTy, ".kmpc_default_loc.addr"));
+ auto DefaultOpenMPLocation = new llvm::GlobalVariable(
+ CGM.getModule(), IdentTy, /*isConstant*/ true,
+ llvm::GlobalValue::PrivateLinkage, /*Initializer*/ nullptr);
DefaultOpenMPLocation->setUnnamedAddr(true);
- DefaultOpenMPLocation->setConstant(true);
- DefaultOpenMPLocation->setLinkage(llvm::GlobalValue::PrivateLinkage);
llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true);
llvm::Constant *Values[] = {Zero,
llvm::ConstantInt::get(CGM.Int32Ty, Flags),
Zero, Zero, DefaultOpenMPPSource};
llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values);
DefaultOpenMPLocation->setInitializer(Init);
+ OpenMPDefaultLocMap[Flags] = DefaultOpenMPLocation;
return DefaultOpenMPLocation;
}
return Entry;
@@ -196,6 +196,14 @@
RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_global_thread_num");
break;
}
+ case OMPRTL__kmpc_barrier: {
+ // Build void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid);
+ llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty};
+ llvm::FunctionType *FnTy =
+ llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+ RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier");
+ break;
+ }
}
return RTLFn;
}
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -238,6 +238,40 @@
/// \brief Captured 'this' type.
FieldDecl *CXXThisFieldDecl;
};
+
+ /// \brief API for captured statement code generation in OpenMP constructs.
+ class CGOpenMPRegionInfo : public CGCapturedStmtInfo {
+ public:
+ CGOpenMPRegionInfo(const OMPExecutableDirective &D, const CapturedStmt &S,
+ const VarDecl *GTidVar)
+ : CGCapturedStmtInfo(S, CR_OpenMP), GTidVar(GTidVar), Directive(D) {}
+
+ virtual ~CGOpenMPRegionInfo() override;
+
+ /// \brief Gets a variable or parameter for storing global thread id
+ /// inside OpenMP construct.
+ const VarDecl *getGTidVariable() const { return GTidVar; }
+
+ static bool classof(const CGCapturedStmtInfo *Info) {
+ return Info->getKind() == CR_OpenMP;
+ }
+
+ /// \brief Emit the captured statement body.
+ virtual void EmitBody(CodeGenFunction &CGF, Stmt *S) override;
+
+ /// \brief Get the name of the capture helper.
+ virtual StringRef getHelperName() const override {
+ return ".omp_outlined.";
+ }
+
+ private:
+ /// \brief A variable or parameter storing global thread id for OpenMP
+ /// constructs.
+ const VarDecl *GTidVar;
+ /// \brief OpenMP executable directive associated with the region.
+ const OMPExecutableDirective &Directive;
+ };
+
CGCapturedStmtInfo *CapturedStmtInfo;
/// BoundsChecking - Emit run-time bounds checks. Higher values mean
@@ -1925,8 +1959,13 @@
const ArrayRef<const Attr *> &Attrs = None);
llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K);
+ void GenerateCapturedStmtFunctionProlog(const CapturedStmt &S);
+ llvm::Function *GenerateCapturedStmtFunctionEpilog(const CapturedStmt &S);
llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S);
llvm::Value *GenerateCapturedStmtArgument(const CapturedStmt &S);
+ typedef llvm::DenseMap<const Decl *, llvm::Value *> OuterDeclMapTy;
+ void EmitOMPPrivateClause(const OMPExecutableDirective &D,
+ OuterDeclMapTy &OuterDeclMap);
void EmitOMPParallelDirective(const OMPParallelDirective &S);
void EmitOMPSimdDirective(const OMPSimdDirective &S);
Index: lib/CodeGen/CGStmtOpenMP.cpp
===================================================================
--- lib/CodeGen/CGStmtOpenMP.cpp
+++ lib/CodeGen/CGStmtOpenMP.cpp
@@ -23,14 +23,65 @@
// OpenMP Directive Emission
//===----------------------------------------------------------------------===//
+void CodeGenFunction::EmitOMPPrivateClause(
+ const OMPExecutableDirective &D,
+ CodeGenFunction::OuterDeclMapTy &OuterDeclMap) {
+ auto PrivateFilter = [](const OMPClause *C) -> bool {
+ return C->getClauseKind() == OMPC_private;
+ };
+ for (OMPExecutableDirective::filtered_clause_iterator<decltype(PrivateFilter)>
+ I(D.clauses(), PrivateFilter); I; ++I) {
+ auto *C = cast<OMPPrivateClause>(*I);
+ auto IRef = C->varlist_begin();
+ for (auto IInit : C->private_copies()) {
+ auto VD = cast<VarDecl>(cast<DeclRefExpr>(IInit)->getDecl());
+ EmitDecl(*VD);
+ OuterDeclMap[cast<DeclRefExpr>(*IRef)->getDecl()] = GetAddrOfLocalVar(VD);
+ ++IRef;
+ }
+ }
+}
+
+CodeGenFunction::CGOpenMPRegionInfo::~CGOpenMPRegionInfo() {}
+
+void CodeGenFunction::CGOpenMPRegionInfo::EmitBody(CodeGenFunction &CGF,
+ Stmt *S) {
+ OuterDeclMapTy OuterDeclMap;
+ CGF.EmitOMPPrivateClause(Directive, OuterDeclMap);
+ if (!OuterDeclMap.empty()) {
+ // Emit implicit barrier to synchronize threads and avoid data races.
+ // Build call __kmpc_barrier(loc, gtid)
+ auto Flags = static_cast<CGOpenMPRuntime::OpenMPLocationFlags>(
+ CGOpenMPRuntime::OMP_IDENT_KMPC |
+ CGOpenMPRuntime::OMP_IDENT_BARRIER_IMPL);
+ llvm::Value *Args[] = {CGF.CGM.getOpenMPRuntime().EmitOpenMPUpdateLocation(
+ CGF, Directive.getLocStart(), Flags),
+ CGF.CGM.getOpenMPRuntime().GetOpenMPGlobalThreadNum(
+ CGF, Directive.getLocStart())};
+ auto RTLFn = CGF.CGM.getOpenMPRuntime().CreateRuntimeFunction(
+ CGOpenMPRuntime::OMPRTL__kmpc_barrier);
+ CGF.EmitRuntimeCall(RTLFn, Args);
+ // Remap captured variables to use their private copies in the outlined
+ // function.
+ for (auto I : OuterDeclMap) {
+ CGF.LocalDeclMap[I.first] = I.second;
+ }
+ }
+ CGCapturedStmtInfo::EmitBody(CGF, S);
+ // Clear mappings of captured private variables.
+ for (auto I : OuterDeclMap) {
+ CGF.LocalDeclMap.erase(I.first);
+ }
+}
+
void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
const CapturedStmt *CS = cast<CapturedStmt>(S.getAssociatedStmt());
llvm::Value *CapturedStruct = GenerateCapturedStmtArgument(*CS);
llvm::Value *OutlinedFn;
{
CodeGenFunction CGF(CGM, true);
- CGCapturedStmtInfo CGInfo(*CS, CS->getCapturedRegionKind());
+ CGOpenMPRegionInfo CGInfo(S, *CS, *CS->getCapturedDecl()->param_begin());
CGF.CapturedStmtInfo = &CGInfo;
OutlinedFn = CGF.GenerateCapturedStmtFunction(*CS);
}
Index: lib/CodeGen/CGOpenMPRuntime.h
===================================================================
--- lib/CodeGen/CGOpenMPRuntime.h
+++ lib/CodeGen/CGOpenMPRuntime.h
@@ -68,7 +68,9 @@
// microtask, ...);
OMPRTL__kmpc_fork_call,
// Call to kmp_int32 kmpc_global_thread_num(ident_t *loc);
- OMPRTL__kmpc_global_thread_num
+ OMPRTL__kmpc_global_thread_num,
+ // Call to void __kmpc_barrier(ident_t *loc, kmp_int32 global_tid);
+ OMPRTL__kmpc_barrier
};
private:
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -1842,6 +1842,10 @@
for (unsigned i = 0; i != NumVars; ++i)
Vars.push_back(Reader->Reader.ReadSubExpr());
C->setVarRefs(Vars);
+ Vars.clear();
+ for (unsigned i = 0; i != NumVars; ++i)
+ Vars.push_back(Reader->Reader.ReadSubExpr());
+ C->setPrivateCopies(Vars);
}
void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -1752,8 +1752,12 @@
void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);
- for (auto *VE : C->varlists())
+ for (auto *VE : C->varlists()) {
+ Writer->Writer.AddStmt(VE);
+ }
+ for (auto *VE : C->private_copies()) {
Writer->Writer.AddStmt(VE);
+ }
}
void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits