diff options
author | Andrew Stubbs <ams@gcc.gnu.org> | 2011-06-07 10:58:16 +0000 |
---|---|---|
committer | Andrew Stubbs <ams@gcc.gnu.org> | 2011-06-07 10:58:16 +0000 |
commit | c536876e065822e33b5c5019d93e527012dda160 (patch) | |
tree | 976e83087ab821ec0d3bd318f9d66c071893b016 /gcc | |
parent | 308dc890dd4315560088e8e012d7ebddf0d887e7 (diff) | |
download | gcc-c536876e065822e33b5c5019d93e527012dda160.zip gcc-c536876e065822e33b5c5019d93e527012dda160.tar.gz gcc-c536876e065822e33b5c5019d93e527012dda160.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/doc/md.texi | 17 | ||||
-rw-r--r-- | gcc/simplify-rtx.c | 84 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/arm/mla-2.c | 9 |
5 files changed, 122 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index eb60a74..a1feeb0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 6fdcce5..0023405 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -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 diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 847a4bb..18f264b 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -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), diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 86d4954..7686e2a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 diff --git a/gcc/testsuite/gcc.target/arm/mla-2.c b/gcc/testsuite/gcc.target/arm/mla-2.c new file mode 100644 index 0000000..bdc508d --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/mla-2.c @@ -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" } } */ |