mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-01-27 21:44:47 +08:00
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:
parent
308dc890dd
commit
c536876e06
@ -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
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
9
gcc/testsuite/gcc.target/arm/mla-2.c
Normal file
9
gcc/testsuite/gcc.target/arm/mla-2.c
Normal 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" } } */
|
Loading…
Reference in New Issue
Block a user