[PATCH] Workaround premature bitfield folding (PR c++/79681)

Richard Biener rguenther@suse.de
Tue Feb 28 15:43:00 GMT 2017


On Tue, 28 Feb 2017, Jakub Jelinek wrote:

> Hi!
> 
> make_bit_field_ref and its callers are invoked not just during GIMPLE (where
> at least fold_truth_andor* isn't really effective; but from what I've tested
> it doesn't do a good job in many cases at GENERIC either, because we
> fold x.btfld == y.btfld too early into ((BIT_FIELD_REF ^ BIT_FIELD_REF) & cst) == 0
> or similar and fold_truth_andor* can't handle that), but also during GENERIC
> and strip away the whole component access path if there are only constant
> offsets (various nested COMPONENT_REFs as well as ARRAY_REFs).  That is not
> really good for constexpr evaluation (we should evaluate constexpr on saved
> fn trees before folding, but that is not GCC7 material), which then can't
> locate where to look for the value.
> 
> This patch just attempts to reuse as much as possible from orig_inner and
> only use adjusted BIT_FIELD_REF on that when in GENERIC (first I've tried to
> use instead COMPONENT_REF with DECL_BIT_FIELD_REPRESENTATIVE, but that isn't
> handled by constexpr.c either).
> Bootstrapped/regtested on x86_64/i686-linux, ok for trunk?

Hmm, I'd rather not do anything is_gimple_form specific.  Can't we
restrict this transform to work on the outermost handled-component only?
Ideally we'd want to find a common base of course.

The folding is also guarded with optimize != 0 so maybe simply disable
it from the FEs?  (but yes, you say it does a bad job on GIMPLE
which is quite understandable as there's no TRUTH_*, but we can
eventually call it from gimplification instead?)

Bah, just not really liking these kind of "hacks"...

Richaard.

> 2017-02-28  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR c++/79681
> 	* fold-const.c (make_bit_field_ref): During FE parsing if orig_inner
> 	is COMPONENT_REF, attempt to use its first operand as BIT_FIELD_REF
> 	base.
> 
> 	* g++.dg/cpp1y/constexpr-79681-1.C: New test.
> 	* g++.dg/cpp1y/constexpr-79681-2.C: New test.
> 
> --- gcc/fold-const.c.jj	2017-02-17 18:29:24.000000000 +0100
> +++ gcc/fold-const.c	2017-02-27 15:05:43.743266260 +0100
> @@ -3862,6 +3862,31 @@ make_bit_field_ref (location_t loc, tree
>  {
>    tree result, bftype;
>  
> +  /* Attempt not to lose access path if possible during FE folding.  */
> +  if (!in_gimple_form && TREE_CODE (orig_inner) == COMPONENT_REF)
> +    {
> +      tree ninner = TREE_OPERAND (orig_inner, 0);
> +      machine_mode nmode;
> +      HOST_WIDE_INT nbitsize, nbitpos;
> +      tree noffset;
> +      int nunsignedp, nreversep, nvolatilep = 0;
> +      tree base = get_inner_reference (ninner, &nbitsize, &nbitpos,
> +				       &noffset, &nmode, &nunsignedp,
> +				       &nreversep, &nvolatilep);
> +      if (base == inner
> +	  && noffset == NULL_TREE
> +	  && nbitsize >= bitsize
> +	  && nbitpos <= bitpos
> +	  && bitpos + bitsize <= nbitpos + nbitsize
> +	  && !reversep
> +	  && !nreversep
> +	  && !nvolatilep)
> +	{
> +	  inner = ninner;
> +	  bitpos -= nbitpos;
> +	}
> +    }
> +
>    alias_set_type iset = get_alias_set (orig_inner);
>    if (iset == 0 && get_alias_set (inner) != iset)
>      inner = fold_build2 (MEM_REF, TREE_TYPE (inner),
> --- gcc/testsuite/g++.dg/cpp1y/constexpr-79681-1.C.jj	2017-02-27 15:11:39.177589060 +0100
> +++ gcc/testsuite/g++.dg/cpp1y/constexpr-79681-1.C	2017-02-27 15:11:28.000000000 +0100
> @@ -0,0 +1,17 @@
> +// PR c++/79681
> +// { dg-do compile { target c++14 } }
> +// { dg-options "-O2" }
> +
> +struct A
> +{
> +  int i : 4;
> +};
> +
> +constexpr bool
> +foo ()
> +{
> +  A x[] = { 1 };
> +  return x[0].i;
> +}
> +
> +static_assert (foo(), "");
> --- gcc/testsuite/g++.dg/cpp1y/constexpr-79681-2.C.jj	2017-02-27 15:11:42.252548562 +0100
> +++ gcc/testsuite/g++.dg/cpp1y/constexpr-79681-2.C	2017-02-27 15:10:13.000000000 +0100
> @@ -0,0 +1,39 @@
> +// PR c++/79681
> +// { dg-do compile { target c++14 } }
> +// { dg-options "-O2" }
> +
> +struct A
> +{
> +  char i : 4;
> +  char k : 1;
> +  char l : 3;
> +};
> +struct B
> +{
> +  char j : 4;
> +};
> +struct C
> +{
> +  long long u;
> +  A a[1];
> +  B b[1];
> +};
> +
> +constexpr bool
> +foo ()
> +{
> +  C c = { 0, { { 5, 0, 2 } }, { { 6 } } };
> +  C d = { 0, { { 6, 0, 1 } }, { { 5 } } };
> +  return c.a[0].i == d.a[0].i && c.b[0].j == d.b[0].j;
> +}
> +
> +constexpr bool
> +bar ()
> +{
> +  C c = { 0, { { 5, 0, 2 } }, { { 6 } } };
> +  C d = { 0, { { 6, 0, 1 } }, { { 5 } } };
> +  return c.a[0].i == d.a[0].i && c.a[0].l == d.a[0].l;
> +}
> +
> +static_assert (foo () == false, "");
> +static_assert (bar () == false, "");
> 
> 	Jakub
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)



More information about the Gcc-patches mailing list