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] catch builtin_bswap16 construct


Christophe Lyon wrote:
> Hi,
> 
> The attached patch catches C constructs:
> (A << 8) | (A >> 8)
> where A is unsigned 16 bits
> and maps them to builtin_bswap16(A) which can provide more efficient
> implementations on some targets.
> 
> The construct above is equivalent to the default bswap16 implementation.
> 
> I have added a testcase for ARM, and have found no regression with
> qemu-arm on arm-none-linux-gnueabi.
> 
> OK?
> 
> Christophe
> 
> 2012-09-19  Christophe Lyon <christophe.lyon@linaro.org>
> 
> 	gcc/
> 	* fold-const.c (fold_binary_loc): call builtin_bswap16 when the
> 	equivalent construct is detected.
> 
> 	gcc/testsuite/
> 	* gcc.target/arm/builtin-bswap-2.c: New testcase.
> 
> diff --git a/gcc/fold-const.c b/gcc/fold-const.c
> index 2bf5179..0ff7e8b 100644
> --- a/gcc/fold-const.c
> +++ b/gcc/fold-const.c
> @@ -10326,6 +10326,99 @@ fold_binary_loc (location_t loc,
>  	  }
>        }
>  
> +      /* Catch bswap16 construct: (A << 8) | (A >> 8) where A is
> +         unsigned 16 bits.
> +         This has been expanded into:
> +	 (ior:SI (lshift:SI (nop:SI A:HI) 8)
> +	         (nop:SI (rshift:HI A:HI 8)))
> +      */

This seems overly complicated on 16-bit platforms where (A << 8) | (A >> 8)
is the same as rotate:HI (A 8).

Does your patch make sure that (A << 8) | (A >> 8) is still mapped to ROTATE
on these targets?

Johann



> +      {
> +	enum tree_code code0, code1;
> +	tree my_arg0 = arg0;
> +	tree my_arg1= arg1;
> +	tree rtype;
> +
> +	code0 = TREE_CODE (arg0);
> +	code1 = TREE_CODE (arg1);
> +	if (code1 == NOP_EXPR)
> +	  {
> +	    my_arg1 = TREE_OPERAND (arg1, 0);
> +	    code1 = TREE_CODE (my_arg1);
> +	  }
> +	else if (code0 == NOP_EXPR)
> +	  {
> +	    my_arg0 = TREE_OPERAND (arg0, 0);
> +	    code0 = TREE_CODE (my_arg0);
> +	  }
> +
> +	/* Handle (A << C1) + (A >> C1).  */
> +	if ((code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR)
> +	     && (TREE_CODE (TREE_OPERAND (my_arg0, 0)) == NOP_EXPR)
> +	     && operand_equal_p (TREE_OPERAND (TREE_OPERAND (my_arg0, 0), 0),
> +				 TREE_OPERAND (my_arg1, 0), 0)
> +	     && (rtype = TREE_TYPE (TREE_OPERAND (my_arg1, 0)),
> +		 TYPE_UNSIGNED (rtype)))
> +	  {
> +	    tree tree01, tree11;
> +	    enum tree_code code01, code11;
> +
> +	    tree01 = TREE_OPERAND (my_arg0, 1);
> +	    tree11 = TREE_OPERAND (my_arg1, 1);
> +	    STRIP_NOPS (tree01);
> +	    STRIP_NOPS (tree11);
> +	    code01 = TREE_CODE (tree01);
> +	    code11 = TREE_CODE (tree11);
> +
> +	    /* Check that shift amount is 8, and input 16 bits wide.  */
> +	    if (code01 == INTEGER_CST
> +		&& code11 == INTEGER_CST
> +		&& TREE_INT_CST_HIGH (tree01) == 0
> +		&& TREE_INT_CST_HIGH (tree11) == 0
> +		&& TREE_INT_CST_LOW (tree01) == TREE_INT_CST_LOW (tree11)
> +		&& TREE_INT_CST_LOW (tree01) == 8
> +		&& TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (my_arg1, 0))) == 16)
> +	      {
> +		tree bswapfn = builtin_decl_explicit (BUILT_IN_BSWAP16);
> +		return build_call_expr_loc (loc, bswapfn, 1,
> +					    TREE_OPERAND (my_arg1, 0));
> +	      }
> +	  }
> +
> +	/* Handle (A >> C1) + (A << C1).  */
> +	else if ((code0 == RSHIFT_EXPR && code1 == LSHIFT_EXPR)
> +		 && (TREE_CODE (TREE_OPERAND (my_arg1, 0)) == NOP_EXPR)
> +		 && operand_equal_p (TREE_OPERAND (TREE_OPERAND (my_arg1, 0),
> +						   0),
> +				     TREE_OPERAND (my_arg0, 0), 0)
> +		 && (rtype = TREE_TYPE (TREE_OPERAND (my_arg0, 0)),
> +		     TYPE_UNSIGNED (rtype)))
> +	  {
> +	    tree tree01, tree11;
> +	    enum tree_code code01, code11;
> +
> +	    tree01 = TREE_OPERAND (my_arg0, 1);
> +	    tree11 = TREE_OPERAND (my_arg1, 1);
> +	    STRIP_NOPS (tree01);
> +	    STRIP_NOPS (tree11);
> +	    code01 = TREE_CODE (tree01);
> +	    code11 = TREE_CODE (tree11);
> +
> +	    /* Check that shift amount is 8, and input 16 bits wide.  */
> +	    if (code01 == INTEGER_CST
> +		&& code11 == INTEGER_CST
> +		&& TREE_INT_CST_HIGH (tree01) == 0
> +		&& TREE_INT_CST_HIGH (tree11) == 0
> +		&& TREE_INT_CST_LOW (tree01) == TREE_INT_CST_LOW (tree11)
> +		&& TREE_INT_CST_LOW (tree01) == 8
> +		&& TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (my_arg0, 0))) == 16)
> +	      {
> +		tree bswapfn = builtin_decl_explicit (BUILT_IN_BSWAP16);
> +		return build_call_expr_loc (loc, bswapfn, 1,
> +					    TREE_OPERAND (my_arg0, 0));
> +	      }
> +	  }
> +      }
> +
>      associate:
>        /* In most languages, can't associate operations on floats through
>  	 parentheses.  Rather than remember where the parentheses were, we
> diff --git a/gcc/testsuite/gcc.target/arm/builtin-bswap-2.c b/gcc/testsuite/gcc.target/arm/builtin-bswap-2.c
> new file mode 100644
> index 0000000..93dbb35
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arm/builtin-bswap-2.c
> @@ -0,0 +1,25 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2" } */
> +/* { dg-require-effective-target arm_arch_v6_ok } */
> +/* { dg-add-options arm_arch_v6 } */
> +/* { dg-final { scan-assembler-not "orr\[ \t\]" } } */
> +
> +unsigned short swapu16_1 (unsigned short x)
> +{
> +  return (x << 8) | (x >> 8);
> +}
> +
> +unsigned short swapu16_2 (unsigned short x)
> +{
> +  return (x >> 8) | (x << 8);
> +}
> +
> +unsigned int swapu32_1 (unsigned int x)
> +{
> +  return (x << 16) | (x >> 16);
> +}
> +
> +unsigned int swapu32_2 (unsigned int x)
> +{
> +  return (x >> 16) | (x << 16);
> +}



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