This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Constant fold VIEW_CONVERT_EXPR


Roger Sayle <roger@eyesopen.com> writes:

> The following patch teaches the middle-end how to fold/evaluate
> VIEW_CONVERT_EXPR of INTEGER_CST, REAL_CST, COMPLEX_CST and VECTOR_CST
> at compile-time.  This type of binary reinterpretation can already
> be performed (for some of the above constant types) in the RTL optimizers,
> and this patch effectively duplicates the logic of simplify-rtx.c's
> simplify_immed_subreg in fold, but operating on trees.
>
> As an example of the immediate benefits consider the following code:
>
>
> 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;
> }
>
> Currently on mainline at the end of the tree-ssa optimizers, in
> .t98.final_cleanup we have:
>
>
> foo ()
> {
>   unsigned int D.1873;
>   unsigned int D.1872;
>
> <bb 2>:
>   D.1872 = VIEW_CONVERT_EXPR<unsigned int>({ 1, 2, 3, 4 });
>   D.1873 = VIEW_CONVERT_EXPR<unsigned int>({ 5, 6, 7, 8 });
>   c = VIEW_CONVERT_EXPR<vector unsigned char>((D.1872 & 2139062143) +
>         (D.1873 & 2139062143) ^ (D.1873 ^ D.1872) & 2155905152);
>   return;
> }
>
> With this patch, we now have the much nicer:
>
> foo ()
> {
> <bb 2>:
>   c = { 6, 8, 10, 12 };
>   return;
> }

 This should be added as a testcase, along with a similar test for
floating point vectors.  If you can add a test of a V_C_E to an integer and
to a floating point constant, that would be great.


> + /* Subroutine of fold_view_convert_expr.  Encode the INTEGER_CST
> +    or REAL_CST specified by EXPR into the buffer PTR.  */
> +
> + static void
> + encode_view_convert_expr (unsigned char *ptr, tree expr)
> + {
> +   tree type = TREE_TYPE (expr);
> +   enum machine_mode mode = TYPE_MODE (type);
> +   int bitsize = GET_MODE_BITSIZE (mode);
> +   int i;

 I think you should have
 gcc_assert(TREE_CODE (expr) == INTEGER_CST || TREE_CODE (expr) == REAL_CST);
here instead of else gcc_unreachable as it is clearer.  The same thing applies
for interpret_view_convert_expr.

> +   if (TREE_CODE (expr) == INTEGER_CST)
> +     {
> +       for (i = 0; i < bitsize; i += 8)
> + 	if (i < HOST_BITS_PER_WIDE_INT)
> + 	  *ptr++ = (unsigned char) (TREE_INT_CST_LOW (expr) >> i);
> + 	else if (i < 2 * HOST_BITS_PER_WIDE_INT)
> + 	  *ptr++ = (unsigned char) (TREE_INT_CST_HIGH (expr)
> + 				    >> (i - HOST_BITS_PER_WIDE_INT));
> + 	/* It shouldn't matter what's done here, so fill with zero.  */
> + 	else
> + 	  *ptr++ = 0;
> +     }
> +   else if (TREE_CODE (expr) == REAL_CST)
> +     {
> +       /* 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];
> +
> +       gcc_assert (bitsize <= 192);
> +       real_to_target (tmp, TREE_REAL_CST_PTR (expr), mode);
> +
> +       for (i = 0; i < bitsize; i += 8)
> + 	{
> + 	  int ibase;
> + 	  if (FLOAT_WORDS_BIG_ENDIAN)
> + 	    ibase = bitsize - 1 - i;
> + 	  else
> + 	    ibase = i;
> + 	  *ptr++ = (unsigned char) (tmp[ibase / 32] >> (i & 31));
> + 	}
> +     }
> +   else
> +     gcc_unreachable ();
> + }
> +
> + /* Subroutine of fold_view_convert_expr.  Interpet the contents of
> +    the buffer PTR as either an INTEGER_CST or REAL_CST of type TYPE,
> +    which must be either INTEGRAL_TYPE_P or SCALAR_FLOAT_TYPE_P respectively.
> +    If the buffer cannot be interpreted, return NULL_TREE.  */
> +
> + static tree
> + interpret_view_convert_expr (unsigned char *ptr, tree type)
> + {
> +   enum machine_mode mode = TYPE_MODE (type);
> +   int bitsize = GET_MODE_BITSIZE (mode);
> +   tree t;
> +   int i;
> +
> +   if (INTEGRAL_TYPE_P (type))
> +     {
> +       unsigned int HOST_WIDE_INT lo = 0;
> +       HOST_WIDE_INT hi = 0;
> +
> +       if (bitsize > 2 * HOST_BITS_PER_WIDE_INT)
> + 	return NULL_TREE;
> +
> +       for (i = 0; i < bitsize; i += 8)
> + 	if (i < HOST_BITS_PER_WIDE_INT)
> + 	  lo |= (unsigned HOST_WIDE_INT) (*ptr++) << i;
> + 	else
> + 	  hi |= (unsigned HOST_WIDE_INT) (*ptr++)
> + 		<< (i - HOST_BITS_PER_WIDE_INT);
> +       t = force_fit_type (build_int_cst_wide (type, lo, hi),
> + 			  0, false, false);
> +     }
> +   else if (SCALAR_FLOAT_TYPE_P (type))
> +     {
> +       /* 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];
> +
> +       if (bitsize > 192)
> + 	return NULL_TREE;
> +       memset (tmp, 0, sizeof (tmp));
> +       for (i = 0; i < bitsize; i += 8)
> + 	{
> + 	  int ibase;
> + 	  if (FLOAT_WORDS_BIG_ENDIAN)
> + 	    ibase = bitsize - 1 - i;
> + 	  else
> + 	    ibase = i;
> + 	  tmp[ibase / 32] |= (long) (*ptr++) << (i & 31);
> + 	}
> +
> +       real_from_target (&r, tmp, mode);
> +       t = build_real (type, r);
> +     }
> +   else
> +     gcc_unreachable ();
> +
> +   return t;
> + }
> +
> +
> + /* 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.  This routine is based heavily on
> +    simplify_immed_subreg.  */
> +
> + static tree
> + fold_view_convert_expr (tree type, tree expr)
> + {
> +   /* We support up to 512-bit values (for V8DFmode).  */
> +   enum {
> +     max_bitsize = 512
> +   };
> +   unsigned char buffer[max_bitsize / 8];
> +   tree etype, elem, elements;
> +   int isize, osize, esize;
> +   unsigned char *ptr;
> +   tree rpart, ipart;
> +   int i, count;
> +
> +   switch (TREE_CODE (expr))
> +     {
> +     case REAL_CST:
> +     case INTEGER_CST:
> +       isize = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (expr)));
> +       if (isize > max_bitsize)
> + 	return NULL_TREE;
> +       encode_view_convert_expr (buffer, expr);
> +       break;
> +
> +     case COMPLEX_CST:
> +       etype = TREE_TYPE (TREE_TYPE (expr));
> +       esize = GET_MODE_BITSIZE (TYPE_MODE (etype));
> +       isize = 2 * esize;
> +       if (isize > max_bitsize)
> + 	return NULL_TREE;
> +       elem = TREE_REALPART (expr);
> +       if (TREE_TYPE (elem) != etype)
> + 	return NULL_TREE;
> +       if (TREE_CODE (elem) != INTEGER_CST && TREE_CODE (elem) != REAL_CST)
> + 	return NULL_TREE;
> +       encode_view_convert_expr (buffer, elem);
> +
> +       ptr = buffer + (esize / 8);
> +       elem = TREE_IMAGPART (expr);
> +       if (TREE_TYPE (elem) != etype)
> + 	return NULL_TREE;
> +       if (TREE_CODE (elem) != INTEGER_CST && TREE_CODE (elem) != REAL_CST)
> + 	return NULL_TREE;
> +       encode_view_convert_expr (ptr, elem);
> +       break;
> +
> +     case VECTOR_CST:
> +       etype = TREE_TYPE (TREE_TYPE (expr));
> +       esize = GET_MODE_BITSIZE (TYPE_MODE (etype));
> +       count = TYPE_VECTOR_SUBPARTS (TREE_TYPE (expr));
> +       isize = count * esize;
> +       if (isize > max_bitsize)
> + 	return NULL_TREE;
> +       elements = TREE_VECTOR_CST_ELTS (expr);
> +       for (i = 0; i < count; i++)
> + 	{
> + 	  /* Vectors are kept in target memory order.  */
> + 	  unsigned byte = (i * esize) / BITS_PER_UNIT;
> + 	  unsigned ibyte = (((count - 1 - i) * esize) / BITS_PER_UNIT);
> + 	  unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte;
> + 	  unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte;
> + 	  unsigned bytele = (subword_byte % UNITS_PER_WORD)
> + 			    + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD;
> + 	  ptr = buffer + (bytele * BITS_PER_UNIT) / 8;
> +
> + 	  if (elements)
> + 	    {
> + 	      elem = TREE_VALUE (elements);
> + 	      elements = TREE_CHAIN (elements);
> + 	    }
> + 	  else
> + 	    elem = NULL_TREE;
> +
> + 	  if (elem)
> + 	    {
> + 	      if (TREE_TYPE (elem) != etype)
> + 		return NULL_TREE;
> + 	      if (TREE_CODE (elem) != INTEGER_CST
> + 		  && TREE_CODE (elem) != REAL_CST)
> + 		return NULL_TREE;
> + 	      encode_view_convert_expr (ptr, elem);
> + 	    }
> + 	  else
> + 	    memset (ptr, 0, esize / 8);
> + 	}
> +       break;
> +
> +     default:
> +       return NULL_TREE;
> +     }
> +
> +   switch (TREE_CODE (type))
> +     {
> +     case INTEGER_TYPE:
> +     case ENUMERAL_TYPE:
> +     case BOOLEAN_TYPE:
> +     case CHAR_TYPE:
> +     case REAL_TYPE:
> +       osize = GET_MODE_BITSIZE (TYPE_MODE (type));
> +       if (osize > isize)
> + 	return NULL_TREE;
> +       return interpret_view_convert_expr (buffer, type);
> +
> +     case COMPLEX_TYPE:
> +       etype = TREE_TYPE (type);
> +       if (!INTEGRAL_TYPE_P (etype) && !SCALAR_FLOAT_TYPE_P (etype))
> + 	return NULL_TREE;
> +       esize = GET_MODE_BITSIZE (TYPE_MODE (etype));
> +       osize = 2 * esize;
> +       if (osize > isize)
> + 	return NULL_TREE;
> +       rpart = interpret_view_convert_expr (buffer, etype);
> +       if (! rpart)
> + 	return NULL_TREE;
> +       ptr = buffer + (esize / 8);
> +       ipart = interpret_view_convert_expr (buffer, etype);
> +       if (! ipart)
> + 	return NULL_TREE;
> +       return build_complex (type, rpart, ipart);
> +
> +     case VECTOR_TYPE:
> +       etype = TREE_TYPE (type);
> +       if (!INTEGRAL_TYPE_P (etype) && !SCALAR_FLOAT_TYPE_P (etype))
> + 	return NULL_TREE;
> +       esize = GET_MODE_BITSIZE (TYPE_MODE (etype));
> +       count = TYPE_VECTOR_SUBPARTS (type);
> +       osize = count * esize;
> +       if (osize > isize)
> + 	return NULL_TREE;
> +       elements = NULL_TREE;
> +       for (i = count-1; i >= 0; i--)
> + 	{
> + 	  /* Vectors are kept in target memory order.  */
> + 	  unsigned byte = (i * esize) / BITS_PER_UNIT;
> + 	  unsigned ibyte = (((count - 1 - i) * esize) / BITS_PER_UNIT);
> + 	  unsigned word_byte = WORDS_BIG_ENDIAN ? ibyte : byte;
> + 	  unsigned subword_byte = BYTES_BIG_ENDIAN ? ibyte : byte;
> + 	  unsigned bytele = (subword_byte % UNITS_PER_WORD)
> + 			    + (word_byte / UNITS_PER_WORD) * UNITS_PER_WORD;
> + 	  ptr = buffer + (bytele * BITS_PER_UNIT) / 8;
> +
> + 	  elem = interpret_view_convert_expr (ptr, etype);
> + 	  if (! elem)
> + 	    return NULL_TREE;
> + 	  elements = tree_cons (NULL_TREE, elem, elements);
> + 	}
> +       return build_vector (type, elements);
> +
> +     default:
> +       break;
> +     }
> +   return NULL_TREE;
> + }
> +
> +
>   /* 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.  */
> *************** fold_unary (enum tree_code code, tree ty
> *** 7040,7046 ****
>
>       case VIEW_CONVERT_EXPR:
>         if (TREE_CODE (op0) == VIEW_CONVERT_EXPR)
> ! 	return build1 (VIEW_CONVERT_EXPR, type, TREE_OPERAND (op0, 0));
>         return NULL_TREE;
>
>       case NEGATE_EXPR:
> --- 7308,7318 ----
>
>       case VIEW_CONVERT_EXPR:
>         if (TREE_CODE (op0) == VIEW_CONVERT_EXPR)
> ! 	return fold_build1 (VIEW_CONVERT_EXPR, type, TREE_OPERAND (op0, 0));
> !       if (TREE_CODE (op0) == INTEGER_CST
> ! 	  || TREE_CODE (op0) == REAL_CST
> ! 	  || TREE_CODE (op0) == VECTOR_CST)
> ! 	return fold_view_convert_expr (type, op0);
>         return NULL_TREE;
>
>       case NEGATE_EXPR:
>
>
> Index: testsuite/gcc.target/i386/20050113-1.c
> ===================================================================
> *** testsuite/gcc.target/i386/20050113-1.c	(revision 109033)
> --- testsuite/gcc.target/i386/20050113-1.c	(working copy)
> ***************
> *** 3,6 ****
>   /* { dg-options "-mmmx" } */
>
>   typedef short int V __attribute__ ((vector_size (8)));
> ! static V v = (V) 0x00FF00FF00FF00FFLL; /* { dg-error "is not constant" } */
> --- 3,6 ----
>   /* { dg-options "-mmmx" } */
>
>   typedef short int V __attribute__ ((vector_size (8)));
> ! static V v = (V) 0x00FF00FF00FF00FFLL;
>
>
> Roger
> --
>
>

-- 
Thanks,
Jim

http://www.csclub.uwaterloo.ca/~ja2morri/
http://phython.blogspot.com
http://open.nit.ca/wiki/?page=jim


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]