simplify-rtx.c (simplify_unary_operation_1): Canonicalize widening multiplies.

2011-06-07  Bernd Schmidt  <bernds@codesourcery.com>
	    Andrew Stubbs  <ams@codesourcery.com>

	gcc/
	* simplify-rtx.c (simplify_unary_operation_1): Canonicalize widening
	multiplies.
	* doc/md.texi (Canonicalization of Instructions): Document widening
	multiply canonicalization.

	gcc/testsuite/
	* gcc.target/arm/mla-2.c: New test.

From-SVN: r174740
This commit is contained in:
Andrew Stubbs 2011-06-07 10:58:16 +00:00
parent 308dc890dd
commit c536876e06
5 changed files with 122 additions and 0 deletions

View File

@ -1,3 +1,11 @@
2011-06-07 Bernd Schmidt <bernds@codesourcery.com>
Andrew Stubbs <ams@codesourcery.com>
* simplify-rtx.c (simplify_unary_operation_1): Canonicalize widening
multiplies.
* doc/md.texi (Canonicalization of Instructions): Document widening
multiply canonicalization.
2011-06-07 Jakub Jelinek <jakub@redhat.com>
PR gcov-profile/49299

View File

@ -5840,6 +5840,23 @@ Equality comparisons of a group of bits (usually a single bit) with zero
will be written using @code{zero_extract} rather than the equivalent
@code{and} or @code{sign_extract} operations.
@cindex @code{mult}, canonicalization of
@item
@code{(sign_extend:@var{m1} (mult:@var{m2} (sign_extend:@var{m2} @var{x})
(sign_extend:@var{m2} @var{y})))} is converted to @code{(mult:@var{m1}
(sign_extend:@var{m1} @var{x}) (sign_extend:@var{m1} @var{y}))}, and likewise
for @code{zero_extend}.
@item
@code{(sign_extend:@var{m1} (mult:@var{m2} (ashiftrt:@var{m2}
@var{x} @var{s}) (sign_extend:@var{m2} @var{y})))} is converted
to @code{(mult:@var{m1} (sign_extend:@var{m1} (ashiftrt:@var{m2}
@var{x} @var{s})) (sign_extend:@var{m1} @var{y}))}, and likewise for
patterns using @code{zero_extend} and @code{lshiftrt}. If the second
operand of @code{mult} is also a shift, then that is extended also.
This transformation is only applied when it can be proven that the
original operation had sufficient precision to prevent overflow.
@end itemize
Further canonicalization rules are defined in the function

View File

@ -1000,6 +1000,48 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == LABEL_REF)
return XEXP (op, 0);
/* Extending a widening multiplication should be canonicalized to
a wider widening multiplication. */
if (GET_CODE (op) == MULT)
{
rtx lhs = XEXP (op, 0);
rtx rhs = XEXP (op, 1);
enum rtx_code lcode = GET_CODE (lhs);
enum rtx_code rcode = GET_CODE (rhs);
/* Widening multiplies usually extend both operands, but sometimes
they use a shift to extract a portion of a register. */
if ((lcode == SIGN_EXTEND
|| (lcode == ASHIFTRT && CONST_INT_P (XEXP (lhs, 1))))
&& (rcode == SIGN_EXTEND
|| (rcode == ASHIFTRT && CONST_INT_P (XEXP (rhs, 1)))))
{
enum machine_mode lmode = GET_MODE (lhs);
enum machine_mode rmode = GET_MODE (rhs);
int bits;
if (lcode == ASHIFTRT)
/* Number of bits not shifted off the end. */
bits = GET_MODE_PRECISION (lmode) - INTVAL (XEXP (lhs, 1));
else /* lcode == SIGN_EXTEND */
/* Size of inner mode. */
bits = GET_MODE_PRECISION (GET_MODE (XEXP (lhs, 0)));
if (rcode == ASHIFTRT)
bits += GET_MODE_PRECISION (rmode) - INTVAL (XEXP (rhs, 1));
else /* rcode == SIGN_EXTEND */
bits += GET_MODE_PRECISION (GET_MODE (XEXP (rhs, 0)));
/* We can only widen multiplies if the result is mathematiclly
equivalent. I.e. if overflow was impossible. */
if (bits <= GET_MODE_PRECISION (GET_MODE (op)))
return simplify_gen_binary
(MULT, mode,
simplify_gen_unary (SIGN_EXTEND, mode, lhs, lmode),
simplify_gen_unary (SIGN_EXTEND, mode, rhs, rmode));
}
}
/* Check for a sign extension of a subreg of a promoted
variable, where the promotion is sign-extended, and the
target mode is the same as the variable's promotion. */
@ -1071,6 +1113,48 @@ simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
return rtl_hooks.gen_lowpart_no_emit (mode, op);
/* Extending a widening multiplication should be canonicalized to
a wider widening multiplication. */
if (GET_CODE (op) == MULT)
{
rtx lhs = XEXP (op, 0);
rtx rhs = XEXP (op, 1);
enum rtx_code lcode = GET_CODE (lhs);
enum rtx_code rcode = GET_CODE (rhs);
/* Widening multiplies usually extend both operands, but sometimes
they use a shift to extract a portion of a register. */
if ((lcode == ZERO_EXTEND
|| (lcode == LSHIFTRT && CONST_INT_P (XEXP (lhs, 1))))
&& (rcode == ZERO_EXTEND
|| (rcode == LSHIFTRT && CONST_INT_P (XEXP (rhs, 1)))))
{
enum machine_mode lmode = GET_MODE (lhs);
enum machine_mode rmode = GET_MODE (rhs);
int bits;
if (lcode == LSHIFTRT)
/* Number of bits not shifted off the end. */
bits = GET_MODE_PRECISION (lmode) - INTVAL (XEXP (lhs, 1));
else /* lcode == ZERO_EXTEND */
/* Size of inner mode. */
bits = GET_MODE_PRECISION (GET_MODE (XEXP (lhs, 0)));
if (rcode == LSHIFTRT)
bits += GET_MODE_PRECISION (rmode) - INTVAL (XEXP (rhs, 1));
else /* rcode == ZERO_EXTEND */
bits += GET_MODE_PRECISION (GET_MODE (XEXP (rhs, 0)));
/* We can only widen multiplies if the result is mathematiclly
equivalent. I.e. if overflow was impossible. */
if (bits <= GET_MODE_PRECISION (GET_MODE (op)))
return simplify_gen_binary
(MULT, mode,
simplify_gen_unary (ZERO_EXTEND, mode, lhs, lmode),
simplify_gen_unary (ZERO_EXTEND, mode, rhs, rmode));
}
}
/* (zero_extend:M (zero_extend:N <X>)) is (zero_extend:M <X>). */
if (GET_CODE (op) == ZERO_EXTEND)
return simplify_gen_unary (ZERO_EXTEND, mode, XEXP (op, 0),

View File

@ -1,3 +1,7 @@
2011-06-07 Andrew Stubbs <ams@codesourcery.com>
* gcc.target/arm/mla-2.c: New test.
2011-06-07 Jakub Jelinek <jakub@redhat.com>
PR gcov-profile/49299

View File

@ -0,0 +1,9 @@
/* { dg-do compile } */
/* { dg-options "-O2 -march=armv7-a" } */
long long foolong (long long x, short *a, short *b)
{
return x + *a * *b;
}
/* { dg-final { scan-assembler "smlalbb" } } */