On Wed, Jun 10, 2015 at 11:38:25AM +0000, Joseph Myers wrote: > This patch, for gomp-4_0-branch, adds support for C++ "this" in > OpenACC directives. (This patch does not do anything to handle OpenMP > differently from OpenACC; that - bug 66053 - will need to be resolved > for mainline, either deciding these cases should be accepted for > OpenMP or making the parsing only accept them in OpenACC directives > and not OpenMP ones.)
So, OpenMP 4.1 is going to accept this only in linear/uniform/aligned clauses and only in #pragma omp declare simd construct. This patch implements this, but as there is no oacc argument to finish_omp_clauses on the trunk/gomp-4_1-branch, I haven't used that to allow it in OpenACC directives, so that will need to be resolved when the branches are merged to trunk. Note I'm afraid your gomp-4_0-branch patch will not do the right thing if you use this outside of non-static member functions (which is why I've added the finish_this_expr for diagnostics). Anyway, committed to gomp4.1 branch. 2015-07-09 Jakub Jelinek <ja...@redhat.com> * parser.c (cp_parser_omp_var_list_no_open): Parse this. * cp-tree.h (finish_omp_declare_simd_methods): New prototype. * semantics.c (handle_omp_array_sections_1): Disallow this based array sections for OpenMP. (finish_omp_declare_simd_methods): New function. (finish_omp_clauses): Don't attempt to adjust linear step of this if it points to TYPE_BEING_DEFINED. Disallow this in all clauses expecting variable lists, except for declare simd linear/uniform/aligned clauses. (finish_struct_1): Call finish_omp_declare_simd_methods. * g++.dg/vect/simd-clone-2.cc: New test. * g++.dg/vect/simd-clone-2.h: New file. * g++.dg/vect/simd-clone-3.cc: New test. * g++.dg/vect/simd-clone-4.cc: New test. * g++.dg/vect/simd-clone-4.h: New file. * g++.dg/vect/simd-clone-5.cc: New test. * g++.dg/gomp/this-1.C: New test. * g++.dg/gomp/this-2.C: New test. --- gcc/cp/parser.c.jj 2015-07-06 13:42:22.000000000 +0200 +++ gcc/cp/parser.c 2015-07-08 11:33:17.255688547 +0200 @@ -27881,15 +27881,26 @@ cp_parser_omp_var_list_no_open (cp_parse tree name, decl; token = cp_lexer_peek_token (parser->lexer); - name = cp_parser_id_expression (parser, /*template_p=*/false, - /*check_dependency_p=*/true, - /*template_p=*/NULL, - /*declarator_p=*/false, - /*optional_p=*/false); - if (name == error_mark_node) - goto skip_comma; + if (current_class_ptr && cp_parser_is_keyword (token, RID_THIS)) + { + decl = finish_this_expr (); + if (TREE_CODE (decl) == NON_LVALUE_EXPR + || CONVERT_EXPR_P (decl)) + decl = TREE_OPERAND (decl, 0); + cp_lexer_consume_token (parser->lexer); + } + else + { + name = cp_parser_id_expression (parser, /*template_p=*/false, + /*check_dependency_p=*/true, + /*template_p=*/NULL, + /*declarator_p=*/false, + /*optional_p=*/false); + if (name == error_mark_node) + goto skip_comma; - decl = cp_parser_lookup_name_simple (parser, name, token->location); + decl = cp_parser_lookup_name_simple (parser, name, token->location); + } if (decl == error_mark_node) cp_parser_name_lookup_error (parser, name, decl, NLE_NULL, token->location); --- gcc/cp/cp-tree.h.jj 2015-07-01 12:50:49.000000000 +0200 +++ gcc/cp/cp-tree.h 2015-07-08 17:27:02.787472523 +0200 @@ -5998,6 +5998,7 @@ extern void note_decl_for_pch (tree); extern tree omp_reduction_id (enum tree_code, tree, tree); extern tree cp_remove_omp_priv_cleanup_stmt (tree *, int *, void *); extern void cp_check_omp_declare_reduction (tree); +extern void finish_omp_declare_simd_methods (tree); extern tree finish_omp_clauses (tree, bool, bool = false); extern tree push_omp_privatization_clauses (bool); extern void pop_omp_privatization_clauses (tree); --- gcc/cp/semantics.c.jj 2015-07-06 19:20:51.000000000 +0200 +++ gcc/cp/semantics.c 2015-07-08 19:26:01.837813436 +0200 @@ -4390,6 +4390,15 @@ handle_omp_array_sections_1 (tree c, tre omp_clause_code_name[OMP_CLAUSE_CODE (c)]); return error_mark_node; } + else if (TREE_CODE (t) == PARM_DECL + && DECL_ARTIFICIAL (t) + && DECL_NAME (t) == this_identifier) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + return error_mark_node; + } else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND && VAR_P (t) && DECL_THREAD_LOCAL_P (t)) { @@ -5491,6 +5500,39 @@ finish_omp_reduction_clause (tree c, boo return false; } +/* Called from finish_struct_1. linear(this) or linear(this:step) + clauses might not be finalized yet because the class has been incomplete + when parsing #pragma omp declare simd methods. Fix those up now. */ + +void +finish_omp_declare_simd_methods (tree t) +{ + if (processing_template_decl) + return; + + for (tree x = TYPE_METHODS (t); x; x = DECL_CHAIN (x)) + { + if (TREE_CODE (TREE_TYPE (x)) != METHOD_TYPE) + continue; + tree ods = lookup_attribute ("omp declare simd", DECL_ATTRIBUTES (x)); + if (!ods || !TREE_VALUE (ods)) + continue; + for (tree c = TREE_VALUE (TREE_VALUE (ods)); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR + && integer_zerop (OMP_CLAUSE_DECL (c)) + && OMP_CLAUSE_LINEAR_STEP (c) + && TREE_CODE (TREE_TYPE (OMP_CLAUSE_LINEAR_STEP (c))) + == POINTER_TYPE) + { + tree s = OMP_CLAUSE_LINEAR_STEP (c); + s = fold_convert_loc (OMP_CLAUSE_LOCATION (c), sizetype, s); + s = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MULT_EXPR, + sizetype, s, TYPE_SIZE_UNIT (t)); + OMP_CLAUSE_LINEAR_STEP (c) = s; + } + } +} + /* For all elements of CLAUSES, validate them vs OpenMP constraints. Remove any elements from the list that are invalid. */ @@ -5626,7 +5668,15 @@ finish_omp_clauses (tree clauses, bool a break; } } - else if (TREE_CODE (type) == POINTER_TYPE) + else if (TREE_CODE (type) == POINTER_TYPE + /* Can't multiply the step yet if *this + is still incomplete type. */ + && (!declare_simd + || TREE_CODE (OMP_CLAUSE_DECL (c)) != PARM_DECL + || !DECL_ARTIFICIAL (OMP_CLAUSE_DECL (c)) + || DECL_NAME (OMP_CLAUSE_DECL (c)) + != this_identifier + || !TYPE_BEING_DEFINED (TREE_TYPE (type)))) { tree d = convert_from_reference (OMP_CLAUSE_DECL (c)); t = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR, @@ -5655,6 +5705,16 @@ finish_omp_clauses (tree clauses, bool a else t = OMP_CLAUSE_DECL (c); check_dup_generic_t: + if (t == current_class_ptr + && (!declare_simd + || (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LINEAR + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_UNIFORM))) + { + error ("%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + remove = true; + break; + } if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL && (!field_ok || TREE_CODE (t) != FIELD_DECL)) { @@ -5696,6 +5756,13 @@ finish_omp_clauses (tree clauses, bool a omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); else t = OMP_CLAUSE_DECL (c); + if (t == current_class_ptr) + { + error ("%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + remove = true; + break; + } if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL && (!allow_fields || TREE_CODE (t) != FIELD_DECL)) { @@ -5723,6 +5790,13 @@ finish_omp_clauses (tree clauses, bool a omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); else t = OMP_CLAUSE_DECL (c); + if (t == current_class_ptr) + { + error ("%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + remove = true; + break; + } if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL && (!allow_fields || TREE_CODE (t) != FIELD_DECL)) { @@ -6000,6 +6074,13 @@ finish_omp_clauses (tree clauses, bool a case OMP_CLAUSE_ALIGNED: t = OMP_CLAUSE_DECL (c); + if (t == current_class_ptr && !declare_simd) + { + error ("%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + remove = true; + break; + } if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { if (processing_template_decl) @@ -6086,6 +6167,12 @@ finish_omp_clauses (tree clauses, bool a error ("%qE is not a variable in %<depend%> clause", t); remove = true; } + else if (t == current_class_ptr) + { + error ("%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + remove = true; + } else if (!processing_template_decl && !cxx_mark_addressable (t)) remove = true; @@ -6139,6 +6226,13 @@ finish_omp_clauses (tree clauses, bool a omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; } + else if (t == current_class_ptr) + { + error ("%<this%> allowed in OpenMP only in %<declare simd%>" + " clauses"); + remove = true; + break; + } else if (!processing_template_decl && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE && !cxx_mark_addressable (t)) --- gcc/cp/class.c.jj 2015-06-30 14:25:15.000000000 +0200 +++ gcc/cp/class.c 2015-07-08 17:06:57.182745066 +0200 @@ -6651,6 +6651,8 @@ finish_struct_1 (tree t) finish_struct_bits (t); set_method_tm_attributes (t); + if (flag_openmp || flag_openmp_simd) + finish_omp_declare_simd_methods (t); /* Complete the rtl for any static member objects of the type we're working on. */ --- gcc/testsuite/g++.dg/vect/simd-clone-2.cc.jj 2015-07-08 18:05:43.898418797 +0200 +++ gcc/testsuite/g++.dg/vect/simd-clone-2.cc 2015-07-08 18:34:57.039683991 +0200 @@ -0,0 +1,55 @@ +// { dg-require-effective-target vect_simd_clones } +// { dg-additional-options "-fopenmp-simd -fno-inline -DONE_FILE" } +// { dg-additional-options "-mavx" { target avx_runtime } } + +#include "../../gcc.dg/vect/tree-vect.h" + +#ifdef ONE_FILE +#include "simd-clone-3.cc" +#else +#include "simd-clone-2.h" +#endif + +T b __attribute__((aligned (32))); + +void +do_main () +{ + int i, r = 0; + S a[64]; + for (i = 0; i < 64; i++) + { + a[i].s = i; + b.t[i] = i; + } + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += a[16].f0 (i); + if (r != 64 * 63 / 2 + 64 * 16) + __builtin_abort (); + r = 0; + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += a[32].f1 (i); + if (r != 64 * 63 / 2 + 64 * 32) + __builtin_abort (); + r = 0; + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += a[i].f2 (i); + if (r != 64 * 63) + __builtin_abort (); + r = 0; + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += b.f3 (i); + if (r != 64 * 63 / 2) + __builtin_abort (); +} + +int +main () +{ + check_vect (); + do_main (); +} --- gcc/testsuite/g++.dg/vect/simd-clone-2.h.jj 2015-07-08 18:06:14.945978075 +0200 +++ gcc/testsuite/g++.dg/vect/simd-clone-2.h 2015-07-08 18:02:21.459292430 +0200 @@ -0,0 +1,17 @@ +struct S +{ + int s; + #pragma omp declare simd notinbranch + int f0 (int x); + #pragma omp declare simd notinbranch uniform(this) + int f1 (int x); + #pragma omp declare simd notinbranch linear(this:sizeof(this)/sizeof(this)) + int f2 (int x); +}; + +struct T +{ + int t[64]; + #pragma omp declare simd aligned(this:32) uniform(this) linear(x) + int f3 (int x); +}; --- gcc/testsuite/g++.dg/vect/simd-clone-3.cc.jj 2015-07-08 18:05:48.203357688 +0200 +++ gcc/testsuite/g++.dg/vect/simd-clone-3.cc 2015-07-08 18:34:23.880149480 +0200 @@ -0,0 +1,34 @@ +// { dg-require-effective-target vect_simd_clones } +// { dg-additional-options "-fopenmp-simd -fno-inline" } +// { dg-additional-options "-mavx" { target avx_runtime } } +// { dg-additional-sources "simd-clone-2.cc" } + +#include "simd-clone-2.h" + +#pragma omp declare simd notinbranch +int +S::f0 (int x) +{ + return x + s; +} + +#pragma omp declare simd notinbranch uniform(this) +int +S::f1 (int x) +{ + return x + s; +} + +#pragma omp declare simd notinbranch linear(this:sizeof(this)/sizeof(this)) +int +S::f2 (int x) +{ + return x + this->S::s; +} + +#pragma omp declare simd uniform(this) aligned(this:32) linear(x) +int +T::f3 (int x) +{ + return t[x]; +} --- gcc/testsuite/g++.dg/vect/simd-clone-4.cc.jj 2015-07-08 18:42:04.371685163 +0200 +++ gcc/testsuite/g++.dg/vect/simd-clone-4.cc 2015-07-08 18:42:23.137421732 +0200 @@ -0,0 +1,55 @@ +// { dg-require-effective-target vect_simd_clones } +// { dg-additional-options "-fopenmp-simd -fno-inline -DONE_FILE" } +// { dg-additional-options "-mavx" { target avx_runtime } } + +#include "../../gcc.dg/vect/tree-vect.h" + +#ifdef ONE_FILE +#include "simd-clone-5.cc" +#else +#include "simd-clone-4.h" +#endif + +T<0> b __attribute__((aligned (32))); + +void +do_main () +{ + int i, r = 0; + S<0> a[64]; + for (i = 0; i < 64; i++) + { + a[i].s = i; + b.t[i] = i; + } + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += a[16].f0 (i); + if (r != 64 * 63 / 2 + 64 * 16) + __builtin_abort (); + r = 0; + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += a[32].f1 (i); + if (r != 64 * 63 / 2 + 64 * 32) + __builtin_abort (); + r = 0; + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += a[i].f2 (i); + if (r != 64 * 63) + __builtin_abort (); + r = 0; + #pragma omp simd reduction(+:r) + for (i = 0; i < 64; i++) + r += b.f3 (i); + if (r != 64 * 63 / 2) + __builtin_abort (); +} + +int +main () +{ + check_vect (); + do_main (); +} --- gcc/testsuite/g++.dg/vect/simd-clone-4.h.jj 2015-07-08 18:42:31.770300545 +0200 +++ gcc/testsuite/g++.dg/vect/simd-clone-4.h 2015-07-08 18:42:45.939101645 +0200 @@ -0,0 +1,19 @@ +template <int N> +struct S +{ + int s; + #pragma omp declare simd notinbranch + int f0 (int x); + #pragma omp declare simd notinbranch uniform(this) + int f1 (int x); + #pragma omp declare simd notinbranch linear(this:sizeof(this)/sizeof(this)) + int f2 (int x); +}; + +template <int N> +struct T +{ + int t[64]; + #pragma omp declare simd aligned(this:32) uniform(this) linear(x) + int f3 (int x); +}; --- gcc/testsuite/g++.dg/vect/simd-clone-5.cc.jj 2015-07-08 18:42:58.486925500 +0200 +++ gcc/testsuite/g++.dg/vect/simd-clone-5.cc 2015-07-08 18:46:28.469983704 +0200 @@ -0,0 +1,41 @@ +// { dg-require-effective-target vect_simd_clones } +// { dg-additional-options "-fopenmp-simd -fno-inline" } +// { dg-additional-options "-mavx" { target avx_runtime } } +// { dg-additional-sources "simd-clone-4.cc" } + +#include "simd-clone-4.h" + +#pragma omp declare simd notinbranch +template <int N> +int +S<N>::f0 (int x) +{ + return x + s; +} + +#pragma omp declare simd notinbranch uniform(this) +template <int N> +int +S<N>::f1 (int x) +{ + return x + s; +} + +#pragma omp declare simd notinbranch linear(this:sizeof(this)/sizeof(this)) +template <int N> +int +S<N>::f2 (int x) +{ + return x + this->S::s; +} + +#pragma omp declare simd uniform(this) aligned(this:32) linear(x) +template <int N> +int +T<N>::f3 (int x) +{ + return t[x]; +} + +template struct S<0>; +template struct T<0>; --- gcc/testsuite/g++.dg/gomp/this-1.C.jj 2015-07-08 18:59:09.101366895 +0200 +++ gcc/testsuite/g++.dg/gomp/this-1.C 2015-07-08 19:28:30.836733226 +0200 @@ -0,0 +1,68 @@ +// { dg-do compile } +// { dg-options "-fopenmp" } + +struct S +{ + #pragma omp declare simd linear(this) // { dg-error "is not an function argument" } + static void foo (); + void bar (); +}; + +void +S::bar () +{ + #pragma omp parallel firstprivate (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp parallel for lastprivate (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + for (int i = 0; i < 10; i++) + ; + #pragma omp parallel shared (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp for linear (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + for (int i = 0; i < 10; i++) + ; + #pragma omp task depend(inout: this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp task depend(inout: this[0]) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp parallel private (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + { + #pragma omp single copyprivate (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + } +} + +template <int N> +struct T +{ + #pragma omp declare simd linear(this) // { dg-error "is not an function argument" } + static void foo (); + void bar (); +}; + +template <int N> +void +T<N>::bar () +{ + #pragma omp parallel firstprivate (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp parallel for lastprivate (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + for (int i = 0; i < 10; i++) + ; + #pragma omp parallel shared (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp for linear (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + for (int i = 0; i < 10; i++) + ; + #pragma omp task depend(inout: this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp task depend(inout: this[0]) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp parallel private (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + { + #pragma omp single copyprivate (this) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + } +} + +template struct T<0>; --- gcc/testsuite/g++.dg/gomp/this-2.C.jj 2015-07-08 18:59:16.693260928 +0200 +++ gcc/testsuite/g++.dg/gomp/this-2.C 2015-07-08 19:46:34.132605144 +0200 @@ -0,0 +1,42 @@ +// { dg-do compile } +// { dg-options "-fopenmp" } + +struct S +{ + void bar (int); +}; + +void +S::bar (int x) +{ + #pragma omp target map (this, x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp target map (this[0], x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp target update to (this, x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + #pragma omp target update to (this[0], x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + #pragma omp target update from (this, x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + #pragma omp target update from (this[1], x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } +} + +template <int N> +struct T +{ + void bar (int); +}; + +template <int N> +void +T<N>::bar (int x) +{ + #pragma omp target map (this, x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp target map (this[0], x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + ; + #pragma omp target update to (this, x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + #pragma omp target update to (this[0], x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + #pragma omp target update from (this, x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } + #pragma omp target update from (this[1], x) // { dg-error ".this. allowed in OpenMP only in .declare simd. clauses" } +} + +template struct T<0>; Jakub