Message ID | 20170907084344.GT2323@tucnak |
---|---|
State | New |
Headers | show |
Series | Fix atomic builtins on arrays (PR target/82112) | expand |
On Thu, 7 Sep 2017, Jakub Jelinek wrote: > Hi! > > The powerpc patch I've just posted led me to try __atomic_* builtins > on arrays as in the testcase below. While it works fine if the > array is just on the first argument or in C, in C++ for arrays in 2nd > or 3rd argument the atomics are rejected (complaining that the argument > is not a pointer), while we should really have performed array-to-pointer > conversion first. > > Fixed thusly, bootstrapped/regtested on powerpc64-linux, ok for trunk? I don't think either the existing or new assertion that arrays only occur in C++ are correct. E.g. build the following with -std=gnu90 so non-lvalue arrays don't decay to pointers. (ICEs on such an assertion in get_atomic_generic_size with a trunk build as of a few days ago.) struct s { int c[10]; }; struct s f (void); void g (void) { __atomic_load ( f().c, f().c, __ATOMIC_ACQUIRE); } (I think C90 non-lvalue arrays there are most appropriately an error, rather than attempting to make them decay to pointers after all.)
On Thu, Sep 07, 2017 at 03:35:00PM +0000, Joseph Myers wrote: > > The powerpc patch I've just posted led me to try __atomic_* builtins > > on arrays as in the testcase below. While it works fine if the > > array is just on the first argument or in C, in C++ for arrays in 2nd > > or 3rd argument the atomics are rejected (complaining that the argument > > is not a pointer), while we should really have performed array-to-pointer > > conversion first. > > > > Fixed thusly, bootstrapped/regtested on powerpc64-linux, ok for trunk? > > I don't think either the existing or new assertion that arrays only occur > in C++ are correct. E.g. build the following with -std=gnu90 so > non-lvalue arrays don't decay to pointers. (ICEs on such an assertion in > get_atomic_generic_size with a trunk build as of a few days ago.) > > struct s { int c[10]; }; > struct s f (void); > void > g (void) > { > __atomic_load ( f().c, f().c, __ATOMIC_ACQUIRE); > } > > (I think C90 non-lvalue arrays there are most appropriately an error, > rather than attempting to make them decay to pointers after all.) Ah, ok, so like this instead? 2017-09-07 Jakub Jelinek <jakub@redhat.com> PR target/82112 * c-common.c (sync_resolve_size): Instead of c_dialect_cxx () assertion check that in the condition. (get_atomic_generic_size): Likewise. Before testing if parameter has pointer type, if it has array type, call for C++ default_conversion to perform array-to-pointer conversion. * c-c++-common/pr82112.c: New test. * gcc.dg/pr82112.c: New test. --- gcc/c-family/c-common.c.jj 2017-09-06 16:23:25.285903973 +0200 +++ gcc/c-family/c-common.c 2017-09-07 22:55:18.836731301 +0200 @@ -6478,10 +6478,9 @@ sync_resolve_size (tree function, vec<tr } argtype = type = TREE_TYPE ((*params)[0]); - if (TREE_CODE (type) == ARRAY_TYPE) + if (TREE_CODE (type) == ARRAY_TYPE && c_dialect_cxx ()) { /* Force array-to-pointer decay for C++. */ - gcc_assert (c_dialect_cxx()); (*params)[0] = default_conversion ((*params)[0]); type = TREE_TYPE ((*params)[0]); } @@ -6646,10 +6645,9 @@ get_atomic_generic_size (location_t loc, /* Get type of first parameter, and determine its size. */ type_0 = TREE_TYPE ((*params)[0]); - if (TREE_CODE (type_0) == ARRAY_TYPE) + if (TREE_CODE (type_0) == ARRAY_TYPE && c_dialect_cxx ()) { /* Force array-to-pointer decay for C++. */ - gcc_assert (c_dialect_cxx()); (*params)[0] = default_conversion ((*params)[0]); type_0 = TREE_TYPE ((*params)[0]); } @@ -6688,6 +6686,12 @@ get_atomic_generic_size (location_t loc, /* __atomic_compare_exchange has a bool in the 4th position, skip it. */ if (n_param == 6 && x == 3) continue; + if (TREE_CODE (type) == ARRAY_TYPE && c_dialect_cxx ()) + { + /* Force array-to-pointer decay for C++. */ + (*params)[x] = default_conversion ((*params)[x]); + type = TREE_TYPE ((*params)[x]); + } if (!POINTER_TYPE_P (type)) { error_at (loc, "argument %d of %qE must be a pointer type", x + 1, --- gcc/testsuite/c-c++-common/pr82112.c.jj 2017-09-07 22:54:39.755185278 +0200 +++ gcc/testsuite/c-c++-common/pr82112.c 2017-09-07 22:54:39.755185278 +0200 @@ -0,0 +1,13 @@ +/* PR target/82112 */ +/* { dg-do compile } */ + +int c[10], d[10], e[10], f[10], g[10], h[10], i[10], j[10], k[10], l[10]; + +void +foo (void) +{ + __atomic_load (c, d, __ATOMIC_ACQUIRE); + __atomic_store (e, f, __ATOMIC_SEQ_CST); + __atomic_exchange (g, h, i, __ATOMIC_RELAXED); + __atomic_compare_exchange (j, k, l, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED); +} --- gcc/testsuite/gcc.dg/pr82112.c.jj 2017-09-07 22:55:59.917254104 +0200 +++ gcc/testsuite/gcc.dg/pr82112.c 2017-09-07 23:07:27.635458611 +0200 @@ -0,0 +1,21 @@ +/* PR target/82112 */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu90" } */ + +struct S { int a[10]; } bar (void); +int b, c; + +void +foo (void) +{ + __atomic_load (bar ().a, &b, __ATOMIC_ACQUIRE); /* { dg-error "argument 1 of .__atomic_load. must be a non-void pointer type" } */ + __atomic_load (&b, bar ().a, __ATOMIC_ACQUIRE); /* { dg-error "argument 2 of .__atomic_load. must be a pointer type" } */ + __atomic_store (bar ().a, &b, __ATOMIC_SEQ_CST); /* { dg-error "argument 1 of .__atomic_store. must be a non-void pointer type" } */ + __atomic_store (&b, bar ().a, __ATOMIC_SEQ_CST); /* { dg-error "argument 2 of .__atomic_store. must be a pointer type" } */ + __atomic_exchange (bar ().a, &b, &c, __ATOMIC_RELAXED); /* { dg-error "argument 1 of .__atomic_exchange. must be a non-void pointer type" } */ + __atomic_exchange (&b, bar ().a, &c, __ATOMIC_RELAXED); /* { dg-error "argument 2 of .__atomic_exchange. must be a pointer type" } */ + __atomic_exchange (&b, &c, bar ().a, __ATOMIC_RELAXED); /* { dg-error "argument 3 of .__atomic_exchange. must be a pointer type" } */ + __atomic_compare_exchange (bar ().a, &b, &c, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED); /* { dg-error "argument 1 of .__atomic_compare_exchange. must be a non-void pointer type" } */ + __atomic_compare_exchange (&b, bar ().a, &c, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED); /* { dg-error "argument 2 of .__atomic_compare_exchange. must be a pointer type" } */ + __atomic_compare_exchange (&b, &c, bar ().a, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED); /* { dg-error "argument 3 of .__atomic_compare_exchange. must be a pointer type" } */ +} Jakub
On Thu, 7 Sep 2017, Jakub Jelinek wrote: > Ah, ok, so like this instead? > > 2017-09-07 Jakub Jelinek <jakub@redhat.com> > > PR target/82112 > * c-common.c (sync_resolve_size): Instead of c_dialect_cxx () > assertion check that in the condition. > (get_atomic_generic_size): Likewise. Before testing if parameter > has pointer type, if it has array type, call for C++ > default_conversion to perform array-to-pointer conversion. > > * c-c++-common/pr82112.c: New test. > * gcc.dg/pr82112.c: New test. This version is OK.
On Thu, Sep 7, 2017 at 11:38 PM, Joseph Myers <joseph@codesourcery.com> wrote: > On Thu, 7 Sep 2017, Jakub Jelinek wrote: > >> Ah, ok, so like this instead? >> >> 2017-09-07 Jakub Jelinek <jakub@redhat.com> >> >> PR target/82112 >> * c-common.c (sync_resolve_size): Instead of c_dialect_cxx () >> assertion check that in the condition. >> (get_atomic_generic_size): Likewise. Before testing if parameter >> has pointer type, if it has array type, call for C++ >> default_conversion to perform array-to-pointer conversion. >> >> * c-c++-common/pr82112.c: New test. >> * gcc.dg/pr82112.c: New test. > > This version is OK. OK with me as well. Jason
--- gcc/c-family/c-common.c.jj 2017-09-01 09:25:35.000000000 +0200 +++ gcc/c-family/c-common.c 2017-09-06 14:47:11.781523252 +0200 @@ -6481,7 +6481,7 @@ sync_resolve_size (tree function, vec<tr if (TREE_CODE (type) == ARRAY_TYPE) { /* Force array-to-pointer decay for C++. */ - gcc_assert (c_dialect_cxx()); + gcc_assert (c_dialect_cxx ()); (*params)[0] = default_conversion ((*params)[0]); type = TREE_TYPE ((*params)[0]); } @@ -6649,7 +6649,7 @@ get_atomic_generic_size (location_t loc, if (TREE_CODE (type_0) == ARRAY_TYPE) { /* Force array-to-pointer decay for C++. */ - gcc_assert (c_dialect_cxx()); + gcc_assert (c_dialect_cxx ()); (*params)[0] = default_conversion ((*params)[0]); type_0 = TREE_TYPE ((*params)[0]); } @@ -6688,6 +6688,13 @@ get_atomic_generic_size (location_t loc, /* __atomic_compare_exchange has a bool in the 4th position, skip it. */ if (n_param == 6 && x == 3) continue; + if (TREE_CODE (type) == ARRAY_TYPE) + { + /* Force array-to-pointer decay for C++. */ + gcc_assert (c_dialect_cxx ()); + (*params)[x] = default_conversion ((*params)[x]); + type = TREE_TYPE ((*params)[x]); + } if (!POINTER_TYPE_P (type)) { error_at (loc, "argument %d of %qE must be a pointer type", x + 1, --- gcc/testsuite/c-c++-common/pr82112.c.jj 2017-09-06 15:21:06.720336134 +0200 +++ gcc/testsuite/c-c++-common/pr82112.c 2017-09-06 15:21:25.138116835 +0200 @@ -0,0 +1,13 @@ +/* PR target/82112 */ +/* { dg-do compile } */ + +int c[10], d[10], e[10], f[10], g[10], h[10], i[10], j[10], k[10], l[10]; + +void +foo (void) +{ + __atomic_load (c, d, __ATOMIC_ACQUIRE); + __atomic_store (e, f, __ATOMIC_SEQ_CST); + __atomic_exchange (g, h, i, __ATOMIC_RELAXED); + __atomic_compare_exchange (j, k, l, 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED); +}