tree-ssa-math-opts.c (convert_mult_to_widen): Better handle unsigned inputs of different modes.

2011-08-19  Andrew Stubbs  <ams@codesourcery.com>

	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.

From-SVN: r177908
This commit is contained in:
Andrew Stubbs 2011-08-19 14:56:24 +00:00 committed by Andrew Stubbs
parent 26a855d7e0
commit 6a228c2c0e
5 changed files with 64 additions and 9 deletions

View File

@ -1,3 +1,9 @@
2011-08-19 Andrew Stubbs <ams@codesourcery.com>
* 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 <ams@codesourcery.com>
* tree-ssa-math-opts.c (is_widening_mult_rhs_p): Add new argument

View File

@ -1,3 +1,8 @@
2011-08-19 Andrew Stubbs <ams@codesourcery.com>
* gcc.target/arm/wmul-9.c: New file.
* gcc.target/arm/wmul-bitfield-2.c: New file.
2011-08-19 Andrew Stubbs <ams@codesourcery.com>
* gcc.target/arm/wmul-8.c: New file.

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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