From 22ffd684d3d01a1780755c665d9ce415cd2a8416 Mon Sep 17 00:00:00 2001 From: ams Date: Fri, 19 Aug 2011 14:56:24 +0000 Subject: [PATCH] 2011-08-19 Andrew Stubbs gcc/ * tree-ssa-math-opts.c (convert_mult_to_widen): Better handle unsigned inputs of different modes. (convert_plusminus_to_widen): Likewise. gcc/testsuite/ * gcc.target/arm/wmul-9.c: New file. * gcc.target/arm/wmul-bitfield-2.c: New file. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@177908 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 6 +++++ gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/gcc.target/arm/wmul-9.c | 11 +++++++++ gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c | 18 ++++++++++++++ gcc/tree-ssa-math-opts.c | 33 +++++++++++++++++++------- 5 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/gcc.target/arm/wmul-9.c create mode 100644 gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5cb610c..648c3b1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2011-08-19 Andrew Stubbs + * tree-ssa-math-opts.c (convert_mult_to_widen): Better handle + unsigned inputs of different modes. + (convert_plusminus_to_widen): Likewise. + +2011-08-19 Andrew Stubbs + * tree-ssa-math-opts.c (is_widening_mult_rhs_p): Add new argument 'type'. Use 'type' from caller, not inferred from 'rhs'. diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 6df6a52..2f65d2e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2011-08-19 Andrew Stubbs + * gcc.target/arm/wmul-9.c: New file. + * gcc.target/arm/wmul-bitfield-2.c: New file. + +2011-08-19 Andrew Stubbs + * gcc.target/arm/wmul-8.c: New file. 2011-08-19 Andrew Stubbs diff --git a/gcc/testsuite/gcc.target/arm/wmul-9.c b/gcc/testsuite/gcc.target/arm/wmul-9.c new file mode 100644 index 0000000..40ed021 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/wmul-9.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target arm_dsp } */ + +long long +foo (long long a, short *b, char *c) +{ + return a + *b * *c; +} + +/* { dg-final { scan-assembler "smlalbb" } } */ diff --git a/gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c b/gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c new file mode 100644 index 0000000..07ba9a8 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/wmul-bitfield-2.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target arm_dsp } */ + +struct bf +{ + int a : 3; + unsigned int b : 15; + int c : 3; +}; + +long long +foo (long long a, struct bf b, struct bf c) +{ + return a + b.b * c.c; +} + +/* { dg-final { scan-assembler "smlalbb" } } */ diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c index bcc02b6..5ba31b5 100644 --- a/gcc/tree-ssa-math-opts.c +++ b/gcc/tree-ssa-math-opts.c @@ -2115,9 +2115,18 @@ convert_mult_to_widen (gimple stmt, gimple_stmt_iterator *gsi) { if (op != smul_widen_optab) { - from_mode = GET_MODE_WIDER_MODE (from_mode); - if (GET_MODE_SIZE (to_mode) <= GET_MODE_SIZE (from_mode)) - return false; + /* We can use a signed multiply with unsigned types as long as + there is a wider mode to use, or it is the smaller of the two + types that is unsigned. Note that type1 >= type2, always. */ + if ((TYPE_UNSIGNED (type1) + && TYPE_PRECISION (type1) == GET_MODE_PRECISION (from_mode)) + || (TYPE_UNSIGNED (type2) + && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode))) + { + from_mode = GET_MODE_WIDER_MODE (from_mode); + if (GET_MODE_SIZE (to_mode) <= GET_MODE_SIZE (from_mode)) + return false; + } op = smul_widen_optab; handler = find_widening_optab_handler_and_mode (op, to_mode, @@ -2284,14 +2293,20 @@ convert_plusminus_to_widen (gimple_stmt_iterator *gsi, gimple stmt, /* There's no such thing as a mixed sign madd yet, so use a wider mode. */ if (from_unsigned1 != from_unsigned2) { - enum machine_mode mode = GET_MODE_WIDER_MODE (from_mode); - if (GET_MODE_PRECISION (mode) < GET_MODE_PRECISION (to_mode)) + /* We can use a signed multiply with unsigned types as long as + there is a wider mode to use, or it is the smaller of the two + types that is unsigned. Note that type1 >= type2, always. */ + if ((from_unsigned1 + && TYPE_PRECISION (type1) == GET_MODE_PRECISION (from_mode)) + || (from_unsigned2 + && TYPE_PRECISION (type2) == GET_MODE_PRECISION (from_mode))) { - from_mode = mode; - from_unsigned1 = from_unsigned2 = false; + from_mode = GET_MODE_WIDER_MODE (from_mode); + if (GET_MODE_SIZE (from_mode) >= GET_MODE_SIZE (to_mode)) + return false; } - else - return false; + + from_unsigned1 = from_unsigned2 = false; } /* If there was a conversion between the multiply and addition -- 2.7.4