* fold-const.c (native_encode_expr): New function to encode
authorsayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 13 Apr 2006 21:10:31 +0000 (21:10 +0000)
committersayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 13 Apr 2006 21:10:31 +0000 (21:10 +0000)
the target representation of an INTEGER_CST, REAL_CST, COMPLEX_CST
or VECTOR_CST into a specified buffer.
(native_encode_int): New function.
(native_encode_real): New function.
(native_encode_complex): New function.
(native_encode_vector): New function.
(native_interpret_expr): Inverse of native_encode_expr to convert
a target representation into an INTEGER_CST, REAL_CST etc...
(native_interpret_int): New function.
(native_interpret_real): New function.
(native_interpret_complex): New function.
(native_interpret_vector): New function.
(fold_view_convert_expr): New function to constant fold/evaluate
a VIEW_CONVERT_EXPR of a suitable constant expression.
(fold_unary) <VIEW_CONVERT_EXPR>: Call fold_view_convert_expr.
Change call of build1 to fold_build1 when constructing a
VIEW_CONVERT_EXPR.

* gcc.target/i386/20050113-1.c: Tweak testcase to reflect that casts
of integers to a vector types are now constant expressions in C.
* gcc.dg/vect/vect-fold-1.c: New test case.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@112927 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/vect/vect-fold-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/20050113-1.c

index d37196d..708551d 100644 (file)
@@ -1,3 +1,24 @@
+2006-04-13  Roger Sayle  <roger@eyesopen.com>
+
+       * fold-const.c (native_encode_expr): New function to encode
+       the target representation of an INTEGER_CST, REAL_CST, COMPLEX_CST
+       or VECTOR_CST into a specified buffer.
+       (native_encode_int): New function.
+       (native_encode_real): New function.
+       (native_encode_complex): New function.
+       (native_encode_vector): New function.
+       (native_interpret_expr): Inverse of native_encode_expr to convert
+       a target representation into an INTEGER_CST, REAL_CST etc...
+       (native_interpret_int): New function.
+       (native_interpret_real): New function.
+       (native_interpret_complex): New function.
+       (native_interpret_vector): New function.
+       (fold_view_convert_expr): New function to constant fold/evaluate
+       a VIEW_CONVERT_EXPR of a suitable constant expression.
+       (fold_unary) <VIEW_CONVERT_EXPR>: Call fold_view_convert_expr.
+       Change call of build1 to fold_build1 when constructing a
+       VIEW_CONVERT_EXPR.
+
 2006-04-13  Paolo Bonzini  <bonzini@gnu.org>
            Ulrich Weigand  <uweigand@de.ibm.com>
 
index d8f7efc..8c88cd3 100644 (file)
@@ -134,6 +134,9 @@ static bool reorder_operands_p (tree, tree);
 static tree fold_negate_const (tree, tree);
 static tree fold_not_const (tree, tree);
 static tree fold_relational_const (enum tree_code, tree, tree, tree);
+static int native_encode_expr (tree, unsigned char *, int);
+static tree native_interpret_expr (tree, unsigned char *, int);
+
 
 /* We know that A1 + B1 = SUM1, using 2's complement arithmetic and ignoring
    overflow.  Suppose A, B and SUM have the same respective signs as A1, B1,
@@ -6756,6 +6759,398 @@ fold_plusminus_mult_expr (enum tree_code code, tree type, tree arg0, tree arg1)
   return NULL_TREE;
 }
 
+/* Subroutine of native_encode_expr.  Encode the INTEGER_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_int (tree expr, unsigned char *ptr, int len)
+{
+  tree type = TREE_TYPE (expr);
+  int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
+  int byte, offset, word, words;
+  unsigned char value;
+
+  if (total_bytes > len)
+    return 0;
+  words = total_bytes / UNITS_PER_WORD;
+
+  for (byte = 0; byte < total_bytes; byte++)
+    {
+      int bitpos = byte * BITS_PER_UNIT;
+      if (bitpos < HOST_BITS_PER_WIDE_INT)
+       value = (unsigned char) (TREE_INT_CST_LOW (expr) >> bitpos);
+      else
+       value = (unsigned char) (TREE_INT_CST_HIGH (expr)
+                                >> (bitpos - HOST_BITS_PER_WIDE_INT));
+
+      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;
+      ptr[offset] = value;
+    }
+  return total_bytes;
+}
+
+
+/* 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
+   upon failure.  */
+
+static int
+native_encode_real (tree expr, unsigned char *ptr, int len)
+{
+  tree type = TREE_TYPE (expr);
+  int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
+  int byte, offset, word, words;
+  unsigned char value;
+
+  /* There are always 32 bits in each long, no matter the size of
+     the hosts long.  We handle floating point representations with
+     up to 192 bits.  */
+  long tmp[6];
+
+  if (total_bytes > len)
+    return 0;
+  words = total_bytes / UNITS_PER_WORD;
+
+  real_to_target (tmp, TREE_REAL_CST_PTR (expr), TYPE_MODE (type));
+
+  for (byte = 0; byte < total_bytes; byte++)
+    {
+      int bitpos = byte * BITS_PER_UNIT;
+      value = (unsigned char) (tmp[bitpos / 32] >> (bitpos & 31));
+
+      if (total_bytes > UNITS_PER_WORD)
+       {
+         word = byte / UNITS_PER_WORD;
+         if (FLOAT_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;
+      ptr[offset] = value;
+    }
+  return total_bytes;
+}
+
+/* Subroutine of native_encode_expr.  Encode the COMPLEX_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_complex (tree expr, unsigned char *ptr, int len)
+{
+  int rsize, isize;
+  tree part;
+
+  part = TREE_REALPART (expr);
+  rsize = native_encode_expr (part, ptr, len);
+  if (rsize == 0)
+    return 0;
+  part = TREE_IMAGPART (expr);
+  isize = native_encode_expr (part, ptr+rsize, len-rsize);
+  if (isize != rsize)
+    return 0;
+  return rsize + isize;
+}
+
+
+/* Subroutine of native_encode_expr.  Encode the VECTOR_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_vector (tree expr, unsigned char *ptr, int len)
+{
+  tree type = TREE_TYPE (expr);
+  int i, size, offste, count;
+  tree elem, elements;
+
+  size = 0;
+  offset = 0;
+  elements = TREE_VECTOR_CST_ELTS (expr);
+  count = TYPE_VECTOR_SUBPARTS (TREE_TYPE (expr));
+  for (i = 0; i < count; i++)
+    {
+      if (elements)
+       {
+         elem = TREE_VALUE (elements);
+         elements = TREE_CHAIN (elements);
+       }
+      else
+       elem = NULL_TREE;
+
+      if (elem)
+       {
+         size = native_encode_expr (elem, ptr+offset, len-offset);
+         if (size == 0)
+           return 0;
+       }
+      else if (size != 0)
+       {
+         if (offset + size > len)
+           return 0;
+         memset (ptr+offset, 0, size);
+       }
+      else
+       return 0;
+      offset += size;
+    }
+  return offset;
+}
+
+
+/* Subroutine of fold_view_convert_expr.  Encode the INTEGER_CST,
+   REAL_CST, COMPLEX_CST or VECTOR_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_expr (tree expr, unsigned char *ptr, int len)
+{
+  switch (TREE_CODE (expr))
+    {
+    case INTEGER_CST:
+      return native_encode_int (expr, ptr, len);
+
+    case REAL_CST:
+      return native_encode_real (expr, ptr, len);
+
+    case COMPLEX_CST:
+      return native_encode_complex (expr, ptr, len);
+
+    case VECTOR_CST:
+      return native_encode_vector (expr, ptr, len);
+
+    default:
+      return 0;
+    }
+}
+
+
+/* Subroutine of native_interpret_expr.  Interpret the contents of
+   the buffer PTR of length LEN as an INTEGER_CST of type TYPE.
+   If the buffer cannot be interpreted, return NULL_TREE.  */
+
+static tree
+native_interpret_int (tree type, unsigned char *ptr, int len)
+{
+  int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
+  int byte, offset, word, words;
+  unsigned char value;
+  unsigned int HOST_WIDE_INT lo = 0;
+  HOST_WIDE_INT hi = 0;
+
+  if (total_bytes > len)
+    return NULL_TREE;
+  if (total_bytes * BITS_PER_UNIT > 2 * HOST_BITS_PER_WIDE_INT)
+    return NULL_TREE;
+  words = total_bytes / UNITS_PER_WORD;
+
+  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];
+
+      if (bitpos < HOST_BITS_PER_WIDE_INT)
+       lo |= (unsigned HOST_WIDE_INT) value << bitpos;
+      else
+       hi |= (unsigned HOST_WIDE_INT) value
+             << (bitpos - HOST_BITS_PER_WIDE_INT);
+    }
+
+  return force_fit_type (build_int_cst_wide (type, lo, hi),
+                        0, false, false);
+}
+
+
+/* Subroutine of native_interpret_expr.  Interpret the contents of
+   the buffer PTR of length LEN as a REAL_CST of type TYPE.
+   If the buffer cannot be interpreted, return NULL_TREE.  */
+
+static tree
+native_interpret_real (tree type, unsigned char *ptr, int len)
+{
+  int total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
+  int byte, offset, word, words;
+  unsigned char value;
+  /* There are always 32 bits in each long, no matter the size of
+     the hosts long.  We handle floating point representations with
+     up to 192 bits.  */
+  REAL_VALUE_TYPE r;
+  long tmp[6];
+
+  total_bytes = GET_MODE_SIZE (TYPE_MODE (type));
+  if (total_bytes > len || total_bytes > 24)
+    return NULL_TREE;
+  words = total_bytes / UNITS_PER_WORD;
+
+  memset (tmp, 0, sizeof (tmp));
+  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 (FLOAT_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];
+
+      tmp[bitpos / 32] |= (unsigned long)value << (bitpos & 31);
+    }
+
+  real_from_target (&r, tmp, mode);
+  return build_real (type, r);
+}
+
+
+/* Subroutine of native_interpret_expr.  Interpret the contents of
+   the buffer PTR of length LEN as a COMPLEX_CST of type TYPE.
+   If the buffer cannot be interpreted, return NULL_TREE.  */
+
+static tree
+native_interpret_complex (tree type, unsigned char *ptr, int len)
+{
+  tree etype, rpart, ipart;
+  int size;
+
+  etype = TREE_TYPE (type);
+  size = GET_MODE_SIZE (TYPE_MODE (etype));
+  if (size * 2 > len)
+    return NULL_TREE;
+  rpart = native_interpret_expr (etype, ptr, size);
+  if (!rpart)
+    return NULL_TREE;
+  ipart = native_interpret_expr (etype, ptr+size, size);
+  if (!ipart)
+    return NULL_TREE;
+  return build_complex (type, rpart, ipart);
+}
+
+
+/* Subroutine of native_interpret_expr.  Interpret the contents of
+   the buffer PTR of length LEN as a VECTOR_CST of type TYPE.
+   If the buffer cannot be interpreted, return NULL_TREE.  */
+
+static tree
+native_interpret_vector (tree type, unsigned char *ptr, int len)
+{
+  tree etype, elem, elements;
+  int i, size, count;
+
+  etype = TREE_TYPE (type);
+  size = GET_MODE_SIZE (TYPE_MODE (etype));
+  count = TYPE_VECTOR_SUBPARTS (type);
+  if (size * count > len)
+    return NULL_TREE;
+
+  elements = NULL_TREE;
+  for (i = count - 1; i >= 0; i--)
+    {
+      elem = native_interpret_expr (etype, ptr+(i*size), size);
+      if (!elem)
+       return NULL_TREE;
+      elements = tree_cons (NULL_TREE, elem, elements);
+    }
+  return build_vector (type, elements);
+}
+
+
+/* Subroutine of fold_view_convert_expr.  Interpet the contents of
+   the buffer PTR of length LEN as a constant of type TYPE.  For
+   INTEGRAL_TYPE_P we return an INTEGER_CST, for SCALAR_FLOAT_TYPE_P
+   we return a REAL_CST, etc...  If the buffer cannot be interpreted,
+   return NULL_TREE.  */
+
+static tree
+native_interpret_expr (tree type, unsigned char *ptr, int len)
+{
+  switch (TREE_CODE (type))
+    {
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+      return native_interpret_int (type, ptr, len);
+
+    case REAL_TYPE:
+      return native_interpret_real (type, ptr, len);
+
+    case COMPLEX_TYPE:
+      return native_interpret_complex (type, ptr, len);
+
+    case VECTOR_TYPE:
+      return native_interpret_vector (type, ptr, len);
+
+    default:
+      return NULL_TREE;
+    }
+}
+
+
+/* Fold a VIEW_CONVERT_EXPR of a constant expression EXPR to type
+   TYPE at compile-time.  If we're unable to perform the conversion
+   return NULL_TREE.  */
+
+static tree
+fold_view_convert_expr (tree type, tree expr)
+{
+  /* We support up to 512-bit values (for V8DFmode).  */
+  unsigned char buffer[64];
+  int len;
+
+  /* Check that the host and target are sane.  */
+  if (CHAR_BIT != 8 || BITS_PER_UNIT != 8)
+    return NULL_TREE;
+
+  len = native_encode_expr (expr, buffer, sizeof (buffer));
+  if (len == 0)
+    return NULL_TREE;
+
+  return native_interpret_expr (type, buffer, len);
+}
+
+
 /* Fold a unary expression of code CODE and type TYPE with operand
    OP0.  Return the folded expression if folding is successful.
    Otherwise, return NULL_TREE.  */
@@ -7095,8 +7490,8 @@ fold_unary (enum tree_code code, tree type, tree op0)
 
     case VIEW_CONVERT_EXPR:
       if (TREE_CODE (op0) == VIEW_CONVERT_EXPR)
-       return build1 (VIEW_CONVERT_EXPR, type, TREE_OPERAND (op0, 0));
-      return NULL_TREE;
+       return fold_build1 (VIEW_CONVERT_EXPR, type, TREE_OPERAND (op0, 0));
+      return fold_view_convert_expr (type, op0);
 
     case NEGATE_EXPR:
       if (negate_expr_p (arg0))
index 2d61f83..185b366 100644 (file)
@@ -1,3 +1,9 @@
+2006-04-13  Roger Sayle  <roger@eyesopen.com>
+
+       * gcc.target/i386/20050113-1.c: Tweak testcase to reflect that casts
+       of integers to a vector types are now constant expressions in C.
+       * gcc.dg/vect/vect-fold-1.c: New test case.
+
 2006-04-13  Paolo Bonzini  <bonzini@gnu.org>
            Ulrich Weigand  <uweigand@de.ibm.com>
 
diff --git a/gcc/testsuite/gcc.dg/vect/vect-fold-1.c b/gcc/testsuite/gcc.dg/vect/vect-fold-1.c
new file mode 100644 (file)
index 0000000..88b68b7
--- /dev/null
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dom1" } */
+
+typedef unsigned char v4qi __attribute__ ((vector_size (4)));
+
+v4qi c;
+
+void foo()
+{
+  v4qi a = { 1, 2, 3, 4 };
+  v4qi b = { 5, 6, 7, 8 };
+  c = a + b;
+}
+
+/* { dg-final { scan-tree-dump-times "c = { 6, 8, 10, 12 }" 1 "dom1" } } */
+/* { dg-final { cleanup-tree-dump "dom1" } } */
index e7f69e3..b1d3cec 100644 (file)
@@ -3,4 +3,4 @@
 /* { dg-options "-mmmx" } */
 
 typedef short int V __attribute__ ((vector_size (8)));
-static V v = (V) 0x00FF00FF00FF00FFLL; /* { dg-error "is not constant" } */
+static V v = (V) 0x00FF00FF00FF00FFLL;