Patchwork PR56064: Fold VIEW_CONVERT_EXPR with FIXED_CST

login
register
mail settings
Submitter Georg-Johann Lay
Date Jan. 21, 2013, 1:28 p.m.
Message ID <50FD4297.1090107@gjlay.de>
Download mbox | patch
Permalink /patch/214149/
State New
Headers show

Comments

Georg-Johann Lay - Jan. 21, 2013, 1:28 p.m.
This is tentative patch as discussed in

http://gcc.gnu.org/ml/gcc/2013-01/msg00187.html

fold-const.c gets 2 new function native_encode_fixed and
native_interpret_fixed.  Code common with the integer case is factored out and
moved to the new constructor-like function double_int::from_buffer.

The code bootstraps fine on x86-linux-gnu and I have test coverage from
avr-unknown-none.

Ok to apply?

There are less intrusive solutions that only handle the int <-> fixed cases,
for example fold-const.c:fold_view_convert_expr() could test for these cases
and use double_int directly without serializing / deserializing through a
memory buffer.

Johann


	PR tree-optimization/56064
	* fixed-value.c (const_fixed_from_double_int): New function.
	* fixed-value.h (const_fixed_from_double_int): New prototype.
	* fold-const.c (native_interpret_fixed): New static function.
	(native_interpret_expr) <FIXED_POINT_TYPE>: Use it.
	(can_native_interpret_type_p) <FIXED_POINT_TYPE>: Return true.
	(native_encode_fixed): New static function.
	(native_encode_expr) <FIXED_CST>: Use it.
	(native_interpret_int): Move double_int worker code to...
	* double-int.c (double_int::from_buffer): ...this new static method.
	* double-int.h (double_int::from_buffer): Prototype it.

testsuite/
	PR tree-optimization/56064
	* gcc.dg/fixed-point/view-convert.c: New test.
Richard Guenther - Jan. 29, 2013, 11:26 a.m.
On Mon, Jan 21, 2013 at 2:28 PM, Georg-Johann Lay <avr@gjlay.de> wrote:
> This is tentative patch as discussed in
>
> http://gcc.gnu.org/ml/gcc/2013-01/msg00187.html
>
> fold-const.c gets 2 new function native_encode_fixed and
> native_interpret_fixed.  Code common with the integer case is factored out and
> moved to the new constructor-like function double_int::from_buffer.
>
> The code bootstraps fine on x86-linux-gnu and I have test coverage from
> avr-unknown-none.
>
> Ok to apply?

Ok.

Thanks,
Richard.

> There are less intrusive solutions that only handle the int <-> fixed cases,
> for example fold-const.c:fold_view_convert_expr() could test for these cases
> and use double_int directly without serializing / deserializing through a
> memory buffer.
>
> Johann
>
>
>         PR tree-optimization/56064
>         * fixed-value.c (const_fixed_from_double_int): New function.
>         * fixed-value.h (const_fixed_from_double_int): New prototype.
>         * fold-const.c (native_interpret_fixed): New static function.
>         (native_interpret_expr) <FIXED_POINT_TYPE>: Use it.
>         (can_native_interpret_type_p) <FIXED_POINT_TYPE>: Return true.
>         (native_encode_fixed): New static function.
>         (native_encode_expr) <FIXED_CST>: Use it.
>         (native_interpret_int): Move double_int worker code to...
>         * double-int.c (double_int::from_buffer): ...this new static method.
>         * double-int.h (double_int::from_buffer): Prototype it.
>
> testsuite/
>         PR tree-optimization/56064
>         * gcc.dg/fixed-point/view-convert.c: New test.

Patch

Index: fixed-value.c
===================================================================
--- fixed-value.c	(revision 195301)
+++ fixed-value.c	(working copy)
@@ -81,6 +81,24 @@  check_real_for_fixed_mode (REAL_VALUE_TY
   return FIXED_OK;
 }
 
+
+/* Construct a CONST_FIXED from a bit payload and machine mode MODE.
+   The bits in PAYLOAD are used verbatim.  */
+
+FIXED_VALUE_TYPE
+const_fixed_from_double_int (double_int payload, enum machine_mode mode)
+{
+  FIXED_VALUE_TYPE value;
+
+  gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT);
+
+  value.data = payload;
+  value.mode = mode;
+
+  return value;
+}
+
+
 /* Initialize from a decimal or hexadecimal string.  */
 
 void
Index: fixed-value.h
===================================================================
--- fixed-value.h	(revision 195301)
+++ fixed-value.h	(working copy)
@@ -49,6 +49,11 @@  extern FIXED_VALUE_TYPE fconst1[MAX_FCON
   const_fixed_from_fixed_value (r, m)
 extern rtx const_fixed_from_fixed_value (FIXED_VALUE_TYPE, enum machine_mode);
 
+/* Construct a CONST_FIXED from a bit payload and machine mode MODE.
+   The bits in PAYLOAD are used verbatim.  */
+extern FIXED_VALUE_TYPE const_fixed_from_double_int (double_int,
+						     enum machine_mode);
+
 /* Initialize from a decimal or hexadecimal string.  */
 extern void fixed_from_string (FIXED_VALUE_TYPE *, const char *,
 			       enum machine_mode);
Index: fold-const.c
===================================================================
--- fold-const.c	(revision 195301)
+++ fold-const.c	(working copy)
@@ -7200,6 +7200,36 @@  native_encode_int (const_tree expr, unsi
 }
 
 
+/* Subroutine of native_encode_expr.  Encode the FIXED_CST
+   specified by EXPR into the buffer PTR of length LEN bytes.
+   Return the number of bytes placed in the buffer, or zero
+   upon failure.  */
+
+static int
+native_encode_fixed (const_tree expr, unsigned char *ptr, int len)
+{
+  tree type = TREE_TYPE (expr);
+  enum machine_mode mode = TYPE_MODE (type);
+  int total_bytes = GET_MODE_SIZE (mode);
+  FIXED_VALUE_TYPE value;
+  tree i_value, i_type;
+
+  if (total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT)
+    return 0;
+
+  i_type = lang_hooks.types.type_for_size (GET_MODE_BITSIZE (mode), 1);
+
+  if (NULL_TREE == i_type
+      || TYPE_PRECISION (i_type) != total_bytes)
+    return 0;
+  
+  value = TREE_FIXED_CST (expr);
+  i_value = double_int_to_tree (i_type, value.data);
+
+  return native_encode_int (i_value, ptr, len);
+}
+
+
 /* Subroutine of native_encode_expr.  Encode the REAL_CST
    specified by EXPR into the buffer PTR of length LEN bytes.
    Return the number of bytes placed in the buffer, or zero
@@ -7345,6 +7375,9 @@  native_encode_expr (const_tree expr, uns
     case REAL_CST:
       return native_encode_real (expr, ptr, len);
 
+    case FIXED_CST:
+      return native_encode_fixed (expr, ptr, len);
+
     case COMPLEX_CST:
       return native_encode_complex (expr, ptr, len);
 
@@ -7368,44 +7401,37 @@  static tree
 native_interpret_int (tree type, const unsigned char *ptr, int len)
 {
   int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
-  int byte, offset, word, words;
-  unsigned char value;
   double_int result;
 
-  if (total_bytes > len)
-    return NULL_TREE;
-  if (total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT)
+  if (total_bytes > len
+      || total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT)
     return NULL_TREE;
 
-  result = double_int_zero;
-  words = total_bytes / UNITS_PER_WORD;
+  result = double_int::from_buffer (ptr, total_bytes);
 
-  for (byte = 0; byte < total_bytes; byte++)
-    {
-      int bitpos = byte * BITS_PER_UNIT;
-      if (total_bytes > UNITS_PER_WORD)
-	{
-	  word = byte / UNITS_PER_WORD;
-	  if (WORDS_BIG_ENDIAN)
-	    word = (words - 1) - word;
-	  offset = word * UNITS_PER_WORD;
-	  if (BYTES_BIG_ENDIAN)
-	    offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD);
-	  else
-	    offset += byte % UNITS_PER_WORD;
-	}
-      else
-	offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
-      value = ptr[offset];
+  return double_int_to_tree (type, result);
+}
 
-      if (bitpos < HOST_BITS_PER_WIDE_INT)
-	result.low |= (unsigned HOST_WIDE_INT) value << bitpos;
-      else
-	result.high |= (unsigned HOST_WIDE_INT) value
-		       << (bitpos - HOST_BITS_PER_WIDE_INT);
-    }
 
-  return double_int_to_tree (type, result);
+/* Subroutine of native_interpret_expr.  Interpret the contents of
+   the buffer PTR of length LEN as a FIXED_CST of type TYPE.
+   If the buffer cannot be interpreted, return NULL_TREE.  */
+
+static tree
+native_interpret_fixed (tree type, const unsigned char *ptr, int len)
+{
+  int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
+  double_int result;
+  FIXED_VALUE_TYPE fixed_value;
+
+  if (total_bytes > len
+      || total_bytes * BITS_PER_UNIT > HOST_BITS_PER_DOUBLE_INT)
+    return NULL_TREE;
+
+  result = double_int::from_buffer (ptr, total_bytes);
+  fixed_value = const_fixed_from_double_int (result, TYPE_MODE (type));
+
+  return build_fixed (type, fixed_value);
 }
 
 
@@ -7533,6 +7559,9 @@  native_interpret_expr (tree type, const
     case REAL_TYPE:
       return native_interpret_real (type, ptr, len);
 
+    case FIXED_POINT_TYPE:
+      return native_interpret_fixed (type, ptr, len);
+
     case COMPLEX_TYPE:
       return native_interpret_complex (type, ptr, len);
 
@@ -7557,6 +7586,7 @@  can_native_interpret_type_p (tree type)
     case BOOLEAN_TYPE:
     case POINTER_TYPE:
     case REFERENCE_TYPE:
+    case FIXED_POINT_TYPE:
     case REAL_TYPE:
     case COMPLEX_TYPE:
     case VECTOR_TYPE:
Index: double-int.c
===================================================================
--- double-int.c	(revision 195301)
+++ double-int.c	(working copy)
@@ -641,6 +641,54 @@  div_and_round_double (unsigned code, int
   return overflow;
 }
 
+
+/* Construct from a buffer of length LEN.  BUFFER will be read according
+   to byte endianess and word endianess.  Only the lower LEN bytes
+   of the result are set; the remaining high bytes are cleared.  */
+
+double_int
+double_int::from_buffer (const unsigned char *buffer, int len)
+{
+  double_int result = double_int_zero;
+  int words = len / UNITS_PER_WORD;
+
+  gcc_assert (len * BITS_PER_UNIT <= HOST_BITS_PER_DOUBLE_INT);
+
+  for (int byte = 0; byte < len; byte++)
+    {
+      int offset;
+      int bitpos = byte * BITS_PER_UNIT;
+      unsigned HOST_WIDE_INT value;
+
+      if (len > UNITS_PER_WORD)
+	{
+	  int word = byte / UNITS_PER_WORD;
+
+	  if (WORDS_BIG_ENDIAN)
+	    word = (words - 1) - word;
+
+	  offset = word * UNITS_PER_WORD;
+
+	  if (BYTES_BIG_ENDIAN)
+	    offset += (UNITS_PER_WORD - 1) - (byte % UNITS_PER_WORD);
+	  else
+	    offset += byte % UNITS_PER_WORD;
+	}
+      else
+	offset = BYTES_BIG_ENDIAN ? (len - 1) - byte : byte;
+
+      value = (unsigned HOST_WIDE_INT) buffer[offset];
+
+      if (bitpos < HOST_BITS_PER_WIDE_INT)
+	result.low |= value << bitpos;
+      else
+	result.high |= value << (bitpos - HOST_BITS_PER_WIDE_INT);
+    }
+
+  return result;
+}
+
+
 /* Returns mask for PREC bits.  */
 
 double_int
Index: double-int.h
===================================================================
--- double-int.h	(revision 195301)
+++ double-int.h	(working copy)
@@ -59,6 +59,10 @@  struct double_int
   static double_int from_shwi (HOST_WIDE_INT cst);
   static double_int from_pair (HOST_WIDE_INT high, unsigned HOST_WIDE_INT low);
 
+  /* Construct from a fuffer of length LEN.  BUFFER will be read according
+     to byte endianess and word endianess.  */
+  static double_int from_buffer (const unsigned char *buffer, int len);
+
   /* No copy assignment operator or destructor to keep the type a POD.  */
 
   /* There are some special value-creation static member functions.  */
Index: testsuite/gcc.dg/fixed-point/view-convert.c
===================================================================
--- testsuite/gcc.dg/fixed-point/view-convert.c	(revision 0)
+++ testsuite/gcc.dg/fixed-point/view-convert.c	(revision 0)
@@ -0,0 +1,122 @@ 
+/* PR tree-optimization/56064 */
+/* { dg-do run } */
+/* { dg-options "-std=gnu99 -O2 -fno-builtin-memcpy" } */
+
+extern void abort (void);
+extern void *memcpy (void*, const void*, __SIZE_TYPE__);
+
+#define f_pun_i(F, I, VAL)                      \
+  {                                             \
+    I i1 = VAL;                                 \
+    I i2 = VAL;                                 \
+    F q1, q2;                                   \
+    memcpy (&q1, &i1, sizeof (I));              \
+    __builtin_memcpy (&q2, &i2, sizeof (I));    \
+    if (q1 != q2)                               \
+      abort();                                  \
+  }
+
+#define i_pun_f(I, F, VAL)                      \
+  {                                             \
+    F q1 = VAL;                                 \
+    F q2 = VAL;                                 \
+    I i1, i2;                                   \
+    memcpy (&i1, &q1, sizeof (I));              \
+    __builtin_memcpy (&i2, &q2, sizeof (I));    \
+    if (i1 != i2)                               \
+      abort();                                  \
+  }
+
+
+void __attribute__((noinline))
+test8 (void)
+{
+#ifdef __INT8_TYPE__
+  if (sizeof (__INT8_TYPE__) == sizeof (short _Fract))
+    {
+#define TEST(X) f_pun_i (short _Fract, __INT8_TYPE__, __INT8_C (X))
+      TEST (123);
+      TEST (-123);
+#undef TEST
+
+#define TEST(X) i_pun_f (__INT8_TYPE__, short _Fract, X ## hr)
+      TEST (0.1234);
+      TEST (-0.987);
+#undef TEST
+    }
+#endif /* __INT8_TYPE__ */
+}
+
+
+void __attribute__((noinline))
+test16 (void)
+{
+#ifdef __INT16_TYPE__
+
+  if (sizeof (__INT16_TYPE__) == sizeof (_Fract))
+    {
+#define TEST(X) f_pun_i (_Fract, __INT16_TYPE__, __INT16_C (X))
+      TEST (0x4321);
+      TEST (-0x4321);
+      TEST (0x8000);
+#undef TEST
+
+#define TEST(X) i_pun_f (__INT16_TYPE__, _Fract, X ## r)
+      TEST (0.12345);
+      TEST (-0.98765);
+#undef TEST
+    }
+#endif /* __INT16_TYPE__ */
+}
+
+
+void __attribute__((noinline))
+test32 (void)
+{
+#ifdef __INT32_TYPE__
+  if (sizeof (__INT32_TYPE__) == sizeof (_Accum))
+    {
+#define TEST(X) f_pun_i (_Accum, __INT32_TYPE__, __INT32_C (X))
+      TEST (0x76543219);
+      TEST (-0x76543219);
+      TEST (0x80000000);
+#undef TEST
+
+#define TEST(X) i_pun_f (__INT32_TYPE__, _Accum, X ## k)
+      TEST (123.456789);
+      TEST (-123.456789);
+#undef TEST
+    }
+#endif /* __INT32_TYPE__ */
+}
+
+
+void __attribute__((noinline))
+test64 (void)
+{
+#ifdef __INT64_TYPE__
+  if (sizeof (__INT64_TYPE__) == sizeof (long _Accum))
+    {
+#define TEST(X) f_pun_i (long _Accum, __INT64_TYPE__, __INT64_C (X))
+      TEST (0x12345678abcdef01);
+      TEST (-0x12345678abcdef01);
+      TEST (0x8000000000000000);
+#undef TEST
+
+#define TEST(X) i_pun_f (__INT64_TYPE__, long _Accum, X ## lk)
+      TEST (123.456789);
+      TEST (-123.456789);
+#undef TEST
+    }
+#endif /* __INT64_TYPE__ */
+}
+
+int main()
+{
+  test8();
+  test16();
+  test32();
+  test64();
+  
+  return 0;
+}