Message ID | 20200422131148.GK2424@tucnak |
---|---|
State | New |
Headers | show |
Series | rs6000: Fix C++14 vs. C++17 ABI bug on powerpc64le [PR94707] | expand |
On 4/22/20 8:11 AM, Jakub Jelinek via Gcc-patches wrote: > Hi! > > As mentioned in the PR and on IRC, the recently added struct-layout-1.exp > new tests FAIL on powerpc64le-linux (among other targets). > FAIL: tmpdir-g++.dg-struct-layout-1/t032 cp_compat_x_tst.o-cp_compat_y_tst.o execute > FAIL: tmpdir-g++.dg-struct-layout-1/t058 cp_compat_x_tst.o-cp_compat_y_tst.o execute > FAIL: tmpdir-g++.dg-struct-layout-1/t059 cp_compat_x_tst.o-cp_compat_y_tst.o execute > in particular. The problem is that the presence or absence of the C++17 > artificial empty base fields, which have non-zero TYPE_SIZE, but zero > DECL_SIZE, change the ABI decisions, if it is present (-std=c++17), the type > might not be considered homogeneous, while if it is absent (-std=c++14), it > can be. > > The following patch fixes that and emits a -Wpsabi inform; perhaps more > often than it could, because the fact that rs6000_discover_homogeneous_aggregate > returns true when it didn't in in GCC 7/8/9 with -std=c++17 doesn't still > mean it will make a different ABI decision, but the warning triggered only > on the test I've changed (the struct-layout-1.exp tests use -w -Wno-psabi > already). > Hm, but this patch violates the ELFv2 ABI as written. The ABI includes: "Floating-point and vector aggregates that contain padding words and integer fields with a width of 0 should not be treated as homogeneous aggregates." So if this patch is accepted, it requires an exception in the ABI document specifically for C++17 empty base fields. Are these base fields required by the C++17 specification? We can't change the ABI just based on a single implementation if it is not required. If it is required, I don't immediately foresee a problem with updating the ABI. Thanks, Bill > > Bootstrapped/regtested on powerpc64le-linux, bootstrapped on powerpc64-linux > where regtest is still pending, but homogeneous aggregates are an ELFv2 > thing, so I don't expect it to change anything (and so far no such messages > appear in the testsuite log files). > > Ok for trunk? > > 2020-04-22 Jakub Jelinek <jakub@redhat.com> > > PR target/94707 > * config/rs6000/rs6000-call.c (rs6000_aggregate_candidate): Add > CXX17_EMPTY_BASE_SEEN argument. Pass it to recursive calls. > Ignore cxx17_empty_base_field_p fields after setting > *CXX17_EMPTY_BASE_SEEN to true. > (rs6000_discover_homogeneous_aggregate): Adjust > rs6000_aggregate_candidate caller. With -Wpsabi, diagnose homogeneous > aggregates with C++17 empty base fields. > > * g++.dg/tree-ssa/pr27830.C: Use -Wpsabi -w for -std=c++17 and higher. > > --- gcc/config/rs6000/rs6000-call.c.jj 2020-03-30 22:53:40.746640328 +0200 > +++ gcc/config/rs6000/rs6000-call.c 2020-04-22 13:05:07.947809888 +0200 > @@ -5528,7 +5528,8 @@ const struct altivec_builtin_types altiv > sub-tree. */ > > static int > -rs6000_aggregate_candidate (const_tree type, machine_mode *modep) > +rs6000_aggregate_candidate (const_tree type, machine_mode *modep, > + bool *cxx17_empty_base_seen) > { > machine_mode mode; > HOST_WIDE_INT size; > @@ -5598,7 +5599,8 @@ rs6000_aggregate_candidate (const_tree t > || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) > return -1; > > - count = rs6000_aggregate_candidate (TREE_TYPE (type), modep); > + count = rs6000_aggregate_candidate (TREE_TYPE (type), modep, > + cxx17_empty_base_seen); > if (count == -1 > || !index > || !TYPE_MAX_VALUE (index) > @@ -5636,7 +5638,14 @@ rs6000_aggregate_candidate (const_tree t > if (TREE_CODE (field) != FIELD_DECL) > continue; > > - sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep); > + if (cxx17_empty_base_field_p (field)) > + { > + *cxx17_empty_base_seen = true; > + continue; > + } > + > + sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep, > + cxx17_empty_base_seen); > if (sub_count < 0) > return -1; > count += sub_count; > @@ -5669,7 +5678,8 @@ rs6000_aggregate_candidate (const_tree t > if (TREE_CODE (field) != FIELD_DECL) > continue; > > - sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep); > + sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep, > + cxx17_empty_base_seen); > if (sub_count < 0) > return -1; > count = count > sub_count ? count : sub_count; > @@ -5710,7 +5720,9 @@ rs6000_discover_homogeneous_aggregate (m > && AGGREGATE_TYPE_P (type)) > { > machine_mode field_mode = VOIDmode; > - int field_count = rs6000_aggregate_candidate (type, &field_mode); > + bool cxx17_empty_base_seen = false; > + int field_count = rs6000_aggregate_candidate (type, &field_mode, > + &cxx17_empty_base_seen); > > if (field_count > 0) > { > @@ -5725,6 +5737,17 @@ rs6000_discover_homogeneous_aggregate (m > *elt_mode = field_mode; > if (n_elts) > *n_elts = field_count; > + if (cxx17_empty_base_seen && warn_psabi) > + { > + static const_tree last_reported_type; > + if (type != last_reported_type) > + { > + inform (input_location, > + "prior to GCC 10, parameters of type " > + "%qT were passed incorrectly for C++17", type); > + last_reported_type = type; > + } > + } > return true; > } > } > --- gcc/testsuite/g++.dg/tree-ssa/pr27830.C.jj 2020-01-11 16:31:54.844296359 +0100 > +++ gcc/testsuite/g++.dg/tree-ssa/pr27830.C 2020-04-22 15:01:37.949881630 +0200 > @@ -1,5 +1,7 @@ > /* { dg-do compile } */ > /* { dg-options "-O" } */ > +/* Ignore ABI warnings for C++17 and later. */ > +/* { dg-additional-options "-Wno-psabi -w" { target c++17 } } */ > > struct gc{}; > struct transform:public gc > > Jakub >
On Wed, Apr 22, 2020 at 11:24:09AM -0500, Bill Schmidt wrote: > Hm, but this patch violates the ELFv2 ABI as written. The ABI includes: > > "Floating-point and vector aggregates that contain padding words and > integer fields with a width of 0 should not be treated as homogeneous > aggregates." struct S {}; struct T : public S { float x, y, z; }; doesn't really contain any padding words nor integer fields with a width of 0, it is laid out as x at offset 0, y at offset sizeof (float) and z at offset sizeof (float) * 2, the struct has sizeof (T) == sizeof (float) * 3. The ELFv2 ABI certainly can't talk about how GCC implements them and what TYPE_FIELDS chain elts should be honored and what should be ignored, it must talk about what is in the source. struct S {}; struct U { struct S s; float x, y, z; }; in C is considered homogeneous and is laid out exactly the same, and so is T in C++14, just in C++17 as an implementation detail the C++ FE adds a base field. Short description + the patch that introduced it is https://gcc.gnu.org/legacy-ml/gcc-patches/2016-10/msg01213.html Jakub
On 4/22/20 11:49 AM, Jakub Jelinek wrote: > On Wed, Apr 22, 2020 at 11:24:09AM -0500, Bill Schmidt wrote: >> Hm, but this patch violates the ELFv2 ABI as written. The ABI includes: >> >> "Floating-point and vector aggregates that contain padding words and >> integer fields with a width of 0 should not be treated as homogeneous >> aggregates." > struct S {}; > struct T : public S { float x, y, z; }; > doesn't really contain any padding words nor integer fields with a width of > 0, it is laid out as x at offset 0, y at offset sizeof (float) and > z at offset sizeof (float) * 2, the struct has sizeof (T) == sizeof (float) * 3. > The ELFv2 ABI certainly can't talk about how GCC implements them and what > TYPE_FIELDS chain elts should be honored and what should be ignored, > it must talk about what is in the source. > struct S {}; > struct U { struct S s; float x, y, z; }; > in C is considered homogeneous and is laid out exactly the same, and so is > T in C++14, just in C++17 as an implementation detail the C++ FE adds a base > field. OK, on reflection I'll accept that. Thanks for the explanation. Bill > Short description + the patch that introduced it is > https://gcc.gnu.org/legacy-ml/gcc-patches/2016-10/msg01213.html > > Jakub >
Hi! On Wed, Apr 22, 2020 at 03:11:48PM +0200, Jakub Jelinek wrote: > The problem is that the presence or absence of the C++17 > artificial empty base fields, which have non-zero TYPE_SIZE, but zero > DECL_SIZE, change the ABI decisions, if it is present (-std=c++17), the type > might not be considered homogeneous, while if it is absent (-std=c++14), it > can be. > > The following patch fixes that and emits a -Wpsabi inform; perhaps more > often than it could, because the fact that rs6000_discover_homogeneous_aggregate > returns true when it didn't in in GCC 7/8/9 with -std=c++17 doesn't still > mean it will make a different ABI decision, but the warning triggered only > on the test I've changed (the struct-layout-1.exp tests use -w -Wno-psabi > already). > PR target/94707 > * config/rs6000/rs6000-call.c (rs6000_aggregate_candidate): Add > CXX17_EMPTY_BASE_SEEN argument. Pass it to recursive calls. > Ignore cxx17_empty_base_field_p fields after setting > *CXX17_EMPTY_BASE_SEEN to true. Please use the literal capitalisation of symbol names? So that grep and other search works (the ALL CAPS thing is for the function introductory comment (and other function comments) only). > + if (cxx17_empty_base_field_p (field)) > + { > + *cxx17_empty_base_seen = true; > + continue; > + } Is there no way to describe this without referring to "c++17" (or even "base field")? It's a pretty gross abstraction violation. > + inform (input_location, > + "prior to GCC 10, parameters of type " > + "%qT were passed incorrectly for C++17", type); This could more explicitly say that makes the compiled code incompatible between GCC 10 and older, which is the point of the warning? It's not really necessary to say the old one was bad -- let's hope it was :-) Looks fine otherwise. Okay for trunk whatever you decide to do (or not do) with my comments. Thank you! Segher
On Wed, Apr 22, 2020 at 05:10:56PM -0500, Segher Boessenkool wrote: > > PR target/94707 > > * config/rs6000/rs6000-call.c (rs6000_aggregate_candidate): Add > > CXX17_EMPTY_BASE_SEEN argument. Pass it to recursive calls. > > Ignore cxx17_empty_base_field_p fields after setting > > *CXX17_EMPTY_BASE_SEEN to true. > > Please use the literal capitalisation of symbol names? So that grep and > other search works (the ALL CAPS thing is for the function introductory > comment (and other function comments) only). Done. > > + if (cxx17_empty_base_field_p (field)) > > + { > > + *cxx17_empty_base_seen = true; > > + continue; > > + } > > Is there no way to describe this without referring to "c++17" (or even > "base field")? It's a pretty gross abstraction violation. I'm afraid it is desirable to talk about c++17 and base field, otherwise it won't be clear what we mean. > > + inform (input_location, > > + "prior to GCC 10, parameters of type " > > + "%qT were passed incorrectly for C++17", type); > > This could more explicitly say that makes the compiled code incompatible > between GCC 10 and older, which is the point of the warning? It's not > really necessary to say the old one was bad -- let's hope it was :-) After many iterations on IRC we came up with the following wording, which is what I've committed. Might be nice to also have URL with larger explanation in changes.html. but the diagnostic framework doesn't support that yet. 2020-04-23 Jakub Jelinek <jakub@redhat.com> PR target/94707 * config/rs6000/rs6000-call.c (rs6000_aggregate_candidate): Add cxx17_empty_base_seen argument. Pass it to recursive calls. Ignore cxx17_empty_base_field_p fields after setting *cxx17_empty_base_seen to true. (rs6000_discover_homogeneous_aggregate): Adjust rs6000_aggregate_candidate caller. With -Wpsabi, diagnose homogeneous aggregates with C++17 empty base fields. * g++.dg/tree-ssa/pr27830.C: Use -Wpsabi -w for -std=c++17 and higher. --- gcc/config/rs6000/rs6000-call.c.jj 2020-03-30 22:53:40.746640328 +0200 +++ gcc/config/rs6000/rs6000-call.c 2020-04-22 13:05:07.947809888 +0200 @@ -5528,7 +5528,8 @@ const struct altivec_builtin_types altiv sub-tree. */ static int -rs6000_aggregate_candidate (const_tree type, machine_mode *modep) +rs6000_aggregate_candidate (const_tree type, machine_mode *modep, + bool *cxx17_empty_base_seen) { machine_mode mode; HOST_WIDE_INT size; @@ -5598,7 +5599,8 @@ rs6000_aggregate_candidate (const_tree t || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) return -1; - count = rs6000_aggregate_candidate (TREE_TYPE (type), modep); + count = rs6000_aggregate_candidate (TREE_TYPE (type), modep, + cxx17_empty_base_seen); if (count == -1 || !index || !TYPE_MAX_VALUE (index) @@ -5636,7 +5638,14 @@ rs6000_aggregate_candidate (const_tree t if (TREE_CODE (field) != FIELD_DECL) continue; - sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep); + if (cxx17_empty_base_field_p (field)) + { + *cxx17_empty_base_seen = true; + continue; + } + + sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep, + cxx17_empty_base_seen); if (sub_count < 0) return -1; count += sub_count; @@ -5669,7 +5678,8 @@ rs6000_aggregate_candidate (const_tree t if (TREE_CODE (field) != FIELD_DECL) continue; - sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep); + sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep, + cxx17_empty_base_seen); if (sub_count < 0) return -1; count = count > sub_count ? count : sub_count; @@ -5710,7 +5720,9 @@ rs6000_discover_homogeneous_aggregate (m && AGGREGATE_TYPE_P (type)) { machine_mode field_mode = VOIDmode; - int field_count = rs6000_aggregate_candidate (type, &field_mode); + bool cxx17_empty_base_seen = false; + int field_count = rs6000_aggregate_candidate (type, &field_mode, + &cxx17_empty_base_seen); if (field_count > 0) { @@ -5725,6 +5737,18 @@ rs6000_discover_homogeneous_aggregate (m *elt_mode = field_mode; if (n_elts) *n_elts = field_count; + if (cxx17_empty_base_seen && warn_psabi) + { + static const_tree last_reported_type; + if (type != last_reported_type) + { + inform (input_location, + "parameter passing for argument of type %qT " + "when C++17 is enabled changed to match C++14 " + "in GCC 10.1", type); + last_reported_type = type; + } + } return true; } } --- gcc/testsuite/g++.dg/tree-ssa/pr27830.C.jj 2020-01-11 16:31:54.844296359 +0100 +++ gcc/testsuite/g++.dg/tree-ssa/pr27830.C 2020-04-22 15:01:37.949881630 +0200 @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O" } */ +/* Ignore ABI warnings for C++17 and later. */ +/* { dg-additional-options "-Wno-psabi -w" { target c++17 } } */ struct gc{}; struct transform:public gc Jakub
Hi! On Thu, Apr 23, 2020 at 10:06:16AM +0200, Jakub Jelinek wrote: > > Is there no way to describe this without referring to "c++17" (or even > > "base field")? It's a pretty gross abstraction violation. > > I'm afraid it is desirable to talk about c++17 and base field, otherwise > it won't be clear what we mean. Yeah, but that just shows it is a bad abstraction (not an abstraction at all really, heh). Not nice :-( > > > + inform (input_location, > > > + "prior to GCC 10, parameters of type " > > > + "%qT were passed incorrectly for C++17", type); > > > > This could more explicitly say that makes the compiled code incompatible > > between GCC 10 and older, which is the point of the warning? It's not > > really necessary to say the old one was bad -- let's hope it was :-) > > After many iterations on IRC we came up with the following wording, which is > what I've committed. Might be nice to also have URL with larger explanation > in changes.html. but the diagnostic framework doesn't support that yet. > + inform (input_location, > + "parameter passing for argument of type %qT " > + "when C++17 is enabled changed to match C++14 " > + "in GCC 10.1", type); It isn't "to match C++14". It simply is a bugfix, we didn't follow the ABI before :-) Thanks again for doing this work, much appreciated, Segher
--- gcc/config/rs6000/rs6000-call.c.jj 2020-03-30 22:53:40.746640328 +0200 +++ gcc/config/rs6000/rs6000-call.c 2020-04-22 13:05:07.947809888 +0200 @@ -5528,7 +5528,8 @@ const struct altivec_builtin_types altiv sub-tree. */ static int -rs6000_aggregate_candidate (const_tree type, machine_mode *modep) +rs6000_aggregate_candidate (const_tree type, machine_mode *modep, + bool *cxx17_empty_base_seen) { machine_mode mode; HOST_WIDE_INT size; @@ -5598,7 +5599,8 @@ rs6000_aggregate_candidate (const_tree t || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) return -1; - count = rs6000_aggregate_candidate (TREE_TYPE (type), modep); + count = rs6000_aggregate_candidate (TREE_TYPE (type), modep, + cxx17_empty_base_seen); if (count == -1 || !index || !TYPE_MAX_VALUE (index) @@ -5636,7 +5638,14 @@ rs6000_aggregate_candidate (const_tree t if (TREE_CODE (field) != FIELD_DECL) continue; - sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep); + if (cxx17_empty_base_field_p (field)) + { + *cxx17_empty_base_seen = true; + continue; + } + + sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep, + cxx17_empty_base_seen); if (sub_count < 0) return -1; count += sub_count; @@ -5669,7 +5678,8 @@ rs6000_aggregate_candidate (const_tree t if (TREE_CODE (field) != FIELD_DECL) continue; - sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep); + sub_count = rs6000_aggregate_candidate (TREE_TYPE (field), modep, + cxx17_empty_base_seen); if (sub_count < 0) return -1; count = count > sub_count ? count : sub_count; @@ -5710,7 +5720,9 @@ rs6000_discover_homogeneous_aggregate (m && AGGREGATE_TYPE_P (type)) { machine_mode field_mode = VOIDmode; - int field_count = rs6000_aggregate_candidate (type, &field_mode); + bool cxx17_empty_base_seen = false; + int field_count = rs6000_aggregate_candidate (type, &field_mode, + &cxx17_empty_base_seen); if (field_count > 0) { @@ -5725,6 +5737,17 @@ rs6000_discover_homogeneous_aggregate (m *elt_mode = field_mode; if (n_elts) *n_elts = field_count; + if (cxx17_empty_base_seen && warn_psabi) + { + static const_tree last_reported_type; + if (type != last_reported_type) + { + inform (input_location, + "prior to GCC 10, parameters of type " + "%qT were passed incorrectly for C++17", type); + last_reported_type = type; + } + } return true; } } --- gcc/testsuite/g++.dg/tree-ssa/pr27830.C.jj 2020-01-11 16:31:54.844296359 +0100 +++ gcc/testsuite/g++.dg/tree-ssa/pr27830.C 2020-04-22 15:01:37.949881630 +0200 @@ -1,5 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O" } */ +/* Ignore ABI warnings for C++17 and later. */ +/* { dg-additional-options "-Wno-psabi -w" { target c++17 } } */ struct gc{}; struct transform:public gc