fold-const: Handle bitfields in native_encode_initializer [PR93121]

Message ID 20200718081541.GI2363@tucnak
State New
Headers show
Series
  • fold-const: Handle bitfields in native_encode_initializer [PR93121]
Related show

Commit Message

Ian Lance Taylor via Gcc-patches July 18, 2020, 8:15 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
native_encode_initializer (those that have integral representative).

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

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

	PR libstdc++/93121
	* fold-const.c (native_encode_initializer): Handle bit-fields.

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


	Jakub

Comments

Richard Biener July 20, 2020, 8:06 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

> native_encode_initializer (those that have integral representative).

> 

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


OK.

Thanks,
Richard.

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

> 

> 	PR libstdc++/93121

> 	* fold-const.c (native_encode_initializer): Handle bit-fields.

> 

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

> 

> --- gcc/fold-const.c.jj	2020-06-24 10:39:48.995469213 +0200

> +++ gcc/fold-const.c	2020-07-17 13:51:53.181392890 +0200

> @@ -8047,6 +8047,7 @@ native_encode_initializer (tree init, un

>  	      tree field = ce->index;

>  	      tree val = ce->value;

>  	      HOST_WIDE_INT pos, fieldsize;

> +	      unsigned HOST_WIDE_INT bpos = 0, epos = 0;

>  

>  	      if (field == NULL_TREE)

>  		return 0;

> @@ -8066,15 +8067,122 @@ native_encode_initializer (tree init, un

>  	      if (fieldsize == 0)

>  		continue;

>  

> +	      if (DECL_BIT_FIELD (field))

> +		{

> +		  if (!tree_fits_uhwi_p (DECL_FIELD_BIT_OFFSET (field)))

> +		    return 0;

> +		  fieldsize = TYPE_PRECISION (TREE_TYPE (field));

> +		  bpos = tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field));

> +		  if (bpos % BITS_PER_UNIT)

> +		    bpos %= BITS_PER_UNIT;

> +		  else

> +		    bpos = 0;

> +		  fieldsize += bpos;

> +		  epos = fieldsize % BITS_PER_UNIT;

> +		  fieldsize += BITS_PER_UNIT - 1;

> +		  fieldsize /= BITS_PER_UNIT;

> +		}

> +

>  	      if (off != -1 && pos + fieldsize <= off)

>  		continue;

>  

> -	      if (DECL_BIT_FIELD (field))

> -		return 0;

> -

>  	      if (val == NULL_TREE)

>  		continue;

>  

> +	      if (DECL_BIT_FIELD (field))

> +		{

> +		  /* FIXME: Handle PDP endian.  */

> +		  if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)

> +		    return 0;

> +

> +		  tree repr = DECL_BIT_FIELD_REPRESENTATIVE (field);

> +		  if (repr == NULL_TREE

> +		      || TREE_CODE (val) != INTEGER_CST

> +		      || !INTEGRAL_TYPE_P (TREE_TYPE (repr)))

> +		    return 0;

> +

> +		  HOST_WIDE_INT rpos = int_byte_position (repr);

> +		  if (rpos > pos)

> +		    return 0;

> +		  wide_int w = wi::to_wide (val,

> +					    TYPE_PRECISION (TREE_TYPE (repr)));

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

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

> +		  HOST_WIDE_INT bitoff = (pos - rpos) * BITS_PER_UNIT + bpos;

> +		  if (!BYTES_BIG_ENDIAN)

> +		    w = wi::lshift (w, bitoff);

> +		  else

> +		    w = wi::lshift (w, diff - bitoff);

> +		  val = wide_int_to_tree (TREE_TYPE (repr), w);

> +

> +		  unsigned char buf[MAX_BITSIZE_MODE_ANY_INT

> +				    / BITS_PER_UNIT + 1];

> +		  int l = native_encode_int (val, buf, sizeof buf, 0);

> +		  if (l * BITS_PER_UNIT != TYPE_PRECISION (TREE_TYPE (repr)))

> +		    return 0;

> +

> +		  if (ptr == NULL)

> +		    continue;

> +

> +		  /* If the bitfield does not start at byte boundary, handle

> +		     the partial byte at the start.  */

> +		  if (bpos

> +		      && (off == -1 || (pos >= off && len >= 1)))

> +		    {

> +		      if (!BYTES_BIG_ENDIAN)

> +			{

> +			  int mask = (1 << bpos) - 1;

> +			  buf[pos - rpos] &= ~mask;

> +			  buf[pos - rpos] |= ptr[pos - o] & mask;

> +			}

> +		      else

> +			{

> +			  int mask = (1 << (BITS_PER_UNIT - bpos)) - 1;

> +			  buf[pos - rpos] &= mask;

> +			  buf[pos - rpos] |= ptr[pos - o] & ~mask;

> +			}

> +		    }

> +		  /* If the bitfield does not end at byte boundary, handle

> +		     the partial byte at the end.  */

> +		  if (epos

> +		      && (off == -1

> +			  || pos + fieldsize <= (HOST_WIDE_INT) off + len))

> +		    {

> +		      if (!BYTES_BIG_ENDIAN)

> +			{

> +			  int mask = (1 << epos) - 1;

> +			  buf[pos - rpos + fieldsize - 1] &= mask;

> +			  buf[pos - rpos + fieldsize - 1]

> +			    |= ptr[pos + fieldsize - 1 - o] & ~mask;

> +			}

> +		       else

> +			{

> +			  int mask = (1 << (BITS_PER_UNIT - epos)) - 1;

> +			  buf[pos - rpos + fieldsize - 1] &= ~mask;

> +			  buf[pos - rpos + fieldsize - 1]

> +			    |= ptr[pos + fieldsize - 1 - o] & mask;

> +			}

> +		    }

> +		  if (off == -1

> +		      || (pos >= off

> +			  && (pos + fieldsize <= (HOST_WIDE_INT) off + len)))

> +		    memcpy (ptr + pos - o, buf + (pos - rpos), fieldsize);

> +		  else

> +		    {

> +		      /* Partial overlap.  */

> +		      HOST_WIDE_INT fsz = fieldsize;

> +		      if (pos < off)

> +			{

> +			  fsz -= (off - pos);

> +			  pos = off;

> +			}

> +		      if (pos + fsz > (HOST_WIDE_INT) off + len)

> +			fsz = (HOST_WIDE_INT) off + len - pos;

> +		      memcpy (ptr + pos - off, buf + (pos - rpos), fsz);

> +		    }

> +		  continue;

> +		}

> +

>  	      if (off == -1

>  		  || (pos >= off

>  		      && (pos + fieldsize <= (HOST_WIDE_INT) off + len)))

> --- gcc/testsuite/gcc.dg/tree-ssa/pr93121-1.c.jj	2020-07-17 13:33:47.106539060 +0200

> +++ gcc/testsuite/gcc.dg/tree-ssa/pr93121-1.c	2020-07-17 13:54:46.786813165 +0200

> @@ -0,0 +1,56 @@

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

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

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

> +

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

> +const union U u = { .b = { 0x7efa3412, 3, 0, 0x50eca8, 0xb, 0x1eeffeed } };

> +const union U v = { .b = { 0x7efa3412, 1, 1, 0x7feedb, 0x5, 0x1eeffeed } };

> +union W { struct T { long long int a, b : 11, c : 3, d : 37, e : 1, f : 10, g : 2, h; } a; int b[6]; short c[12]; long long d[3]; };

> +const union W w = { .a = { 0x0feedbacdeadbeefLL, -1011, 2, -0xbacdeadbeLL, -1, 721, 1, 0x0feedbacdeadbeefLL } };

> +int a, b, c, d, e, f, g, h, i, j, k, l;

> +long long m;

> +

> +void

> +foo ()

> +{

> +  a = u.a[1];

> +  b = v.a[1];

> +  c = u.c[2];

> +  d = u.c[3];

> +  e = v.c[2];

> +  f = v.c[3];

> +  g = w.b[2];

> +  h = w.b[3];

> +  i = w.c[4];

> +  j = w.c[5];

> +  k = w.c[6];

> +  l = w.c[7];

> +  m = w.d[1];

> +}

> +

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

> +/* { dg-final { scan-tree-dump-times "m = -9103311533965288635;" 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/fold-const.c.jj	2020-06-24 10:39:48.995469213 +0200
+++ gcc/fold-const.c	2020-07-17 13:51:53.181392890 +0200
@@ -8047,6 +8047,7 @@  native_encode_initializer (tree init, un
 	      tree field = ce->index;
 	      tree val = ce->value;
 	      HOST_WIDE_INT pos, fieldsize;
+	      unsigned HOST_WIDE_INT bpos = 0, epos = 0;
 
 	      if (field == NULL_TREE)
 		return 0;
@@ -8066,15 +8067,122 @@  native_encode_initializer (tree init, un
 	      if (fieldsize == 0)
 		continue;
 
+	      if (DECL_BIT_FIELD (field))
+		{
+		  if (!tree_fits_uhwi_p (DECL_FIELD_BIT_OFFSET (field)))
+		    return 0;
+		  fieldsize = TYPE_PRECISION (TREE_TYPE (field));
+		  bpos = tree_to_uhwi (DECL_FIELD_BIT_OFFSET (field));
+		  if (bpos % BITS_PER_UNIT)
+		    bpos %= BITS_PER_UNIT;
+		  else
+		    bpos = 0;
+		  fieldsize += bpos;
+		  epos = fieldsize % BITS_PER_UNIT;
+		  fieldsize += BITS_PER_UNIT - 1;
+		  fieldsize /= BITS_PER_UNIT;
+		}
+
 	      if (off != -1 && pos + fieldsize <= off)
 		continue;
 
-	      if (DECL_BIT_FIELD (field))
-		return 0;
-
 	      if (val == NULL_TREE)
 		continue;
 
+	      if (DECL_BIT_FIELD (field))
+		{
+		  /* FIXME: Handle PDP endian.  */
+		  if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+		    return 0;
+
+		  tree repr = DECL_BIT_FIELD_REPRESENTATIVE (field);
+		  if (repr == NULL_TREE
+		      || TREE_CODE (val) != INTEGER_CST
+		      || !INTEGRAL_TYPE_P (TREE_TYPE (repr)))
+		    return 0;
+
+		  HOST_WIDE_INT rpos = int_byte_position (repr);
+		  if (rpos > pos)
+		    return 0;
+		  wide_int w = wi::to_wide (val,
+					    TYPE_PRECISION (TREE_TYPE (repr)));
+		  int diff = (TYPE_PRECISION (TREE_TYPE (repr))
+			      - TYPE_PRECISION (TREE_TYPE (field)));
+		  HOST_WIDE_INT bitoff = (pos - rpos) * BITS_PER_UNIT + bpos;
+		  if (!BYTES_BIG_ENDIAN)
+		    w = wi::lshift (w, bitoff);
+		  else
+		    w = wi::lshift (w, diff - bitoff);
+		  val = wide_int_to_tree (TREE_TYPE (repr), w);
+
+		  unsigned char buf[MAX_BITSIZE_MODE_ANY_INT
+				    / BITS_PER_UNIT + 1];
+		  int l = native_encode_int (val, buf, sizeof buf, 0);
+		  if (l * BITS_PER_UNIT != TYPE_PRECISION (TREE_TYPE (repr)))
+		    return 0;
+
+		  if (ptr == NULL)
+		    continue;
+
+		  /* If the bitfield does not start at byte boundary, handle
+		     the partial byte at the start.  */
+		  if (bpos
+		      && (off == -1 || (pos >= off && len >= 1)))
+		    {
+		      if (!BYTES_BIG_ENDIAN)
+			{
+			  int mask = (1 << bpos) - 1;
+			  buf[pos - rpos] &= ~mask;
+			  buf[pos - rpos] |= ptr[pos - o] & mask;
+			}
+		      else
+			{
+			  int mask = (1 << (BITS_PER_UNIT - bpos)) - 1;
+			  buf[pos - rpos] &= mask;
+			  buf[pos - rpos] |= ptr[pos - o] & ~mask;
+			}
+		    }
+		  /* If the bitfield does not end at byte boundary, handle
+		     the partial byte at the end.  */
+		  if (epos
+		      && (off == -1
+			  || pos + fieldsize <= (HOST_WIDE_INT) off + len))
+		    {
+		      if (!BYTES_BIG_ENDIAN)
+			{
+			  int mask = (1 << epos) - 1;
+			  buf[pos - rpos + fieldsize - 1] &= mask;
+			  buf[pos - rpos + fieldsize - 1]
+			    |= ptr[pos + fieldsize - 1 - o] & ~mask;
+			}
+		       else
+			{
+			  int mask = (1 << (BITS_PER_UNIT - epos)) - 1;
+			  buf[pos - rpos + fieldsize - 1] &= ~mask;
+			  buf[pos - rpos + fieldsize - 1]
+			    |= ptr[pos + fieldsize - 1 - o] & mask;
+			}
+		    }
+		  if (off == -1
+		      || (pos >= off
+			  && (pos + fieldsize <= (HOST_WIDE_INT) off + len)))
+		    memcpy (ptr + pos - o, buf + (pos - rpos), fieldsize);
+		  else
+		    {
+		      /* Partial overlap.  */
+		      HOST_WIDE_INT fsz = fieldsize;
+		      if (pos < off)
+			{
+			  fsz -= (off - pos);
+			  pos = off;
+			}
+		      if (pos + fsz > (HOST_WIDE_INT) off + len)
+			fsz = (HOST_WIDE_INT) off + len - pos;
+		      memcpy (ptr + pos - off, buf + (pos - rpos), fsz);
+		    }
+		  continue;
+		}
+
 	      if (off == -1
 		  || (pos >= off
 		      && (pos + fieldsize <= (HOST_WIDE_INT) off + len)))
--- gcc/testsuite/gcc.dg/tree-ssa/pr93121-1.c.jj	2020-07-17 13:33:47.106539060 +0200
+++ gcc/testsuite/gcc.dg/tree-ssa/pr93121-1.c	2020-07-17 13:54:46.786813165 +0200
@@ -0,0 +1,56 @@ 
+/* PR libstdc++/93121 */
+/* { dg-do compile { target { ilp32 || lp64 } } } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+union U { int a[3]; short c[6]; struct S { int d; int a : 2; int f : 1; int b : 24; int c : 5; int e; } b; };
+const union U u = { .b = { 0x7efa3412, 3, 0, 0x50eca8, 0xb, 0x1eeffeed } };
+const union U v = { .b = { 0x7efa3412, 1, 1, 0x7feedb, 0x5, 0x1eeffeed } };
+union W { struct T { long long int a, b : 11, c : 3, d : 37, e : 1, f : 10, g : 2, h; } a; int b[6]; short c[12]; long long d[3]; };
+const union W w = { .a = { 0x0feedbacdeadbeefLL, -1011, 2, -0xbacdeadbeLL, -1, 721, 1, 0x0feedbacdeadbeefLL } };
+int a, b, c, d, e, f, g, h, i, j, k, l;
+long long m;
+
+void
+foo ()
+{
+  a = u.a[1];
+  b = v.a[1];
+  c = u.c[2];
+  d = u.c[3];
+  e = v.c[2];
+  f = v.c[3];
+  g = w.b[2];
+  h = w.b[3];
+  i = w.c[4];
+  j = w.c[5];
+  k = w.c[6];
+  l = w.c[7];
+  m = w.d[1];
+}
+
+/* { dg-final { scan-tree-dump-times "a = 1518822723;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "b = 738162397;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "c = 25923;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "d = 23175;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "e = 30429;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "f = 11263;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "g = 1418761229;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "h = 1830622408;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "i = -27635;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "j = 21648;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "k = 5320;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "l = 27933;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "m = 7862463375103529997;" 1 "optimized" { target le } } } */
+/* { dg-final { scan-tree-dump-times "a = -904030965;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "b = 1878907749;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "c = -13795;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "d = -27381;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "e = 28669;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "f = -9371;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "g = -2119529884;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "h = 709385029;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "i = -32342;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "j = -30108;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "k = 10824;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "l = 23365;" 1 "optimized" { target be } } } */
+/* { dg-final { scan-tree-dump-times "m = -9103311533965288635;" 1 "optimized" { target be } } } */