gimple-fold: Handle bitfields in fold_const_aggregate_ref_1 [PR93121]

Message ID 20200718081738.GJ2363@tucnak
State New
Headers show
Series
  • gimple-fold: Handle bitfields in fold_const_aggregate_ref_1 [PR93121]
Related show

Commit Message

Bill Schmidt via Gcc-patches July 18, 2020, 8:17 a.m.
Hi!

When working on __builtin_bit_cast that needs to handle bitfields too,
I've made the following change to handle at least some bitfields in
fold_const_aggregate_ref_1 (those that have integral representative).
It already handles some, but only those that start and end at byte
boundaries.

Bootstrapped/regtested on {x86_64,i686,powerpc64{,le}}-linux, ok for trunk?

2020-07-18  Jakub Jelinek  <jakub@redhat.com>

	PR libstdc++/93121
	* gimple-fold.c (fold_const_aggregate_ref_1): For COMPONENT_REF
	of a bitfield not aligned on byte boundaries try to
	fold_ctor_reference DECL_BIT_FIELD_REPRESENTATIVE if any and
	adjust it depending on endianity.

	* gcc.dg/tree-ssa/pr93121-2.c: New test.



	Jakub

Comments

Richard Biener July 20, 2020, 8:16 a.m. | #1
On Sat, 18 Jul 2020, Jakub Jelinek wrote:

> Hi!

> 

> When working on __builtin_bit_cast that needs to handle bitfields too,

> I've made the following change to handle at least some bitfields in

> fold_const_aggregate_ref_1 (those that have integral representative).

> It already handles some, but only those that start and end at byte

> boundaries.

> 

> Bootstrapped/regtested on {x86_64,i686,powerpc64{,le}}-linux, ok for trunk?


OK.

Richard.

> 2020-07-18  Jakub Jelinek  <jakub@redhat.com>

> 

> 	PR libstdc++/93121

> 	* gimple-fold.c (fold_const_aggregate_ref_1): For COMPONENT_REF

> 	of a bitfield not aligned on byte boundaries try to

> 	fold_ctor_reference DECL_BIT_FIELD_REPRESENTATIVE if any and

> 	adjust it depending on endianity.

> 

> 	* gcc.dg/tree-ssa/pr93121-2.c: New test.

> 

> --- gcc/gimple-fold.c.jj	2020-07-13 19:09:33.218871556 +0200

> +++ gcc/gimple-fold.c	2020-07-17 19:17:59.694537680 +0200

> @@ -7189,8 +7189,64 @@ fold_const_aggregate_ref_1 (tree t, tree

>        if (maybe_lt (offset, 0))

>  	return NULL_TREE;

>  

> -      return fold_ctor_reference (TREE_TYPE (t), ctor, offset, size,

> -				  base);

> +      tem = fold_ctor_reference (TREE_TYPE (t), ctor, offset, size, base);

> +      if (tem)

> +	return tem;

> +

> +      /* For bit field reads try to read the representative and

> +	 adjust.  */

> +      if (TREE_CODE (t) == COMPONENT_REF

> +	  && DECL_BIT_FIELD (TREE_OPERAND (t, 1))

> +	  && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)))

> +	{

> +	  HOST_WIDE_INT csize, coffset;

> +	  tree field = TREE_OPERAND (t, 1);

> +	  tree repr = DECL_BIT_FIELD_REPRESENTATIVE (field);

> +	  if (INTEGRAL_TYPE_P (TREE_TYPE (repr))

> +	      && size.is_constant (&csize)

> +	      && offset.is_constant (&coffset)

> +	      && (coffset % BITS_PER_UNIT != 0

> +		  || csize % BITS_PER_UNIT != 0)

> +	      && !reverse

> +	      && BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN)

> +	    {

> +	      poly_int64 bitoffset;

> +	      poly_uint64 field_offset, repr_offset;

> +	      if (poly_int_tree_p (DECL_FIELD_OFFSET (field), &field_offset)

> +		  && poly_int_tree_p (DECL_FIELD_OFFSET (repr), &repr_offset))

> +		bitoffset = (field_offset - repr_offset) * BITS_PER_UNIT;

> +	      else

> +		bitoffset = 0;

> +	      bitoffset += (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field))

> +			    - tree_to_uhwi (DECL_FIELD_BIT_OFFSET (repr)));

> +	      HOST_WIDE_INT bitoff;

> +	      int diff = (TYPE_PRECISION (TREE_TYPE (repr))

> +			  - TYPE_PRECISION (TREE_TYPE (field)));

> +	      if (bitoffset.is_constant (&bitoff)

> +		  && bitoff >= 0

> +		  && bitoff <= diff)

> +		{

> +		  offset -= bitoff;

> +		  size = tree_to_uhwi (DECL_SIZE (repr));

> +

> +		  tem = fold_ctor_reference (TREE_TYPE (repr), ctor, offset,

> +					     size, base);

> +		  if (tem && TREE_CODE (tem) == INTEGER_CST)

> +		    {

> +		      if (!BYTES_BIG_ENDIAN)

> +			tem = wide_int_to_tree (TREE_TYPE (field),

> +						wi::lrshift (wi::to_wide (tem),

> +							     bitoff));

> +		      else

> +			tem = wide_int_to_tree (TREE_TYPE (field),

> +						wi::lrshift (wi::to_wide (tem),

> +							     diff - bitoff));

> +		      return tem;

> +		    }

> +		}

> +	    }

> +	}

> +      break;

>  

>      case REALPART_EXPR:

>      case IMAGPART_EXPR:

> --- gcc/testsuite/gcc.dg/tree-ssa/pr93121-2.c.jj	2020-07-17 19:47:31.842426096 +0200

> +++ gcc/testsuite/gcc.dg/tree-ssa/pr93121-2.c	2020-07-17 19:48:24.551649910 +0200

> @@ -0,0 +1,22 @@

> +/* PR libstdc++/93121 */

> +/* { dg-do compile { target { ilp32 || lp64 } } } */

> +/* { dg-options "-O2 -fdump-tree-optimized" } */

> +

> +union U { int a[3]; struct S { int d; int a : 3; int b : 24; int c : 5; int e; } b; };

> +const union U u = { .a = { 0x7efa3412, 0x5a876543, 0x1eeffeed } };

> +int a, b, c;

> +

> +void

> +foo ()

> +{

> +  a = u.b.a;

> +  b = u.b.b;

> +  c = u.b.c;

> +}

> +

> +/* { dg-final { scan-tree-dump-times "a = 3;" 1 "optimized" { target le } } } */

> +/* { dg-final { scan-tree-dump-times "b = 5303464;" 1 "optimized" { target le } } } */

> +/* { dg-final { scan-tree-dump-times "c = 11;" 1 "optimized" { target le } } } */

> +/* { dg-final { scan-tree-dump-times "a = 2;" 1 "optimized" { target be } } } */

> +/* { dg-final { scan-tree-dump-times "b = -2868438;" 1 "optimized" { target be } } } */

> +/* { dg-final { scan-tree-dump-times "c = 3;" 1 "optimized" { target be } } } */

> 

> 

> 	Jakub

> 

> 


-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)

Patch

--- gcc/gimple-fold.c.jj	2020-07-13 19:09:33.218871556 +0200
+++ gcc/gimple-fold.c	2020-07-17 19:17:59.694537680 +0200
@@ -7189,8 +7189,64 @@  fold_const_aggregate_ref_1 (tree t, tree
       if (maybe_lt (offset, 0))
 	return NULL_TREE;
 
-      return fold_ctor_reference (TREE_TYPE (t), ctor, offset, size,
-				  base);
+      tem = fold_ctor_reference (TREE_TYPE (t), ctor, offset, size, base);
+      if (tem)
+	return tem;
+
+      /* For bit field reads try to read the representative and
+	 adjust.  */
+      if (TREE_CODE (t) == COMPONENT_REF
+	  && DECL_BIT_FIELD (TREE_OPERAND (t, 1))
+	  && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)))
+	{
+	  HOST_WIDE_INT csize, coffset;
+	  tree field = TREE_OPERAND (t, 1);
+	  tree repr = DECL_BIT_FIELD_REPRESENTATIVE (field);
+	  if (INTEGRAL_TYPE_P (TREE_TYPE (repr))
+	      && size.is_constant (&csize)
+	      && offset.is_constant (&coffset)
+	      && (coffset % BITS_PER_UNIT != 0
+		  || csize % BITS_PER_UNIT != 0)
+	      && !reverse
+	      && BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN)
+	    {
+	      poly_int64 bitoffset;
+	      poly_uint64 field_offset, repr_offset;
+	      if (poly_int_tree_p (DECL_FIELD_OFFSET (field), &field_offset)
+		  && poly_int_tree_p (DECL_FIELD_OFFSET (repr), &repr_offset))
+		bitoffset = (field_offset - repr_offset) * BITS_PER_UNIT;
+	      else
+		bitoffset = 0;
+	      bitoffset += (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field))
+			    - tree_to_uhwi (DECL_FIELD_BIT_OFFSET (repr)));
+	      HOST_WIDE_INT bitoff;
+	      int diff = (TYPE_PRECISION (TREE_TYPE (repr))
+			  - TYPE_PRECISION (TREE_TYPE (field)));
+	      if (bitoffset.is_constant (&bitoff)
+		  && bitoff >= 0
+		  && bitoff <= diff)
+		{
+		  offset -= bitoff;
+		  size = tree_to_uhwi (DECL_SIZE (repr));
+
+		  tem = fold_ctor_reference (TREE_TYPE (repr), ctor, offset,
+					     size, base);
+		  if (tem && TREE_CODE (tem) == INTEGER_CST)
+		    {
+		      if (!BYTES_BIG_ENDIAN)
+			tem = wide_int_to_tree (TREE_TYPE (field),
+						wi::lrshift (wi::to_wide (tem),
+							     bitoff));
+		      else
+			tem = wide_int_to_tree (TREE_TYPE (field),
+						wi::lrshift (wi::to_wide (tem),
+							     diff - bitoff));
+		      return tem;
+		    }
+		}
+	    }
+	}
+      break;
 
     case REALPART_EXPR:
     case IMAGPART_EXPR:
--- gcc/testsuite/gcc.dg/tree-ssa/pr93121-2.c.jj	2020-07-17 19:47:31.842426096 +0200
+++ gcc/testsuite/gcc.dg/tree-ssa/pr93121-2.c	2020-07-17 19:48:24.551649910 +0200
@@ -0,0 +1,22 @@ 
+/* PR libstdc++/93121 */
+/* { dg-do compile { target { ilp32 || lp64 } } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+union U { int a[3]; struct S { int d; int a : 3; int b : 24; int c : 5; int e; } b; };
+const union U u = { .a = { 0x7efa3412, 0x5a876543, 0x1eeffeed } };
+int a, b, c;
+
+void
+foo ()
+{
+  a = u.b.a;
+  b = u.b.b;
+  c = u.b.c;
+}
+
+/* { dg-final { scan-tree-dump-times "a = 3;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "b = 5303464;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "c = 11;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "a = 2;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "b = -2868438;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "c = 3;" 1 "optimized" { target be } } } */