expmed.c (expand_mult): Use synthetic multiplication sequences for more classes of DImode...

* expmed.c (expand_mult): Use synthetic multiplication sequences for
	more classes of DImode multiplication by constant.  Allow both
	multiplication by small negative constants (by performing a
	multiplication by a positive constant and negating the result) and
	multiplications by large powers of two, by using a left shift.

From-SVN: r96377
This commit is contained in:
Roger Sayle 2005-03-13 17:06:42 +00:00 committed by Roger Sayle
parent 92c54d2c4e
commit 65dc935013
2 changed files with 88 additions and 41 deletions

View File

@ -1,3 +1,11 @@
2005-03-13 Roger Sayle <roger@eyesopen.com>
* expmed.c (expand_mult): Use synthetic multiplication sequences for
more classes of DImode multiplication by constant. Allow both
multiplication by small negative constants (by performing a
multiplication by a positive constant and negating the result) and
multiplications by large powers of two, by using a left shift.
2005-03-13 Kazu Hirata <kazu@cs.umass.edu>
* tree-into-ssa.c (find_idf): Speed up by putting the indexes

View File

@ -3011,57 +3011,96 @@ rtx
expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
int unsignedp)
{
rtx const_op1 = op1;
enum mult_variant variant;
struct algorithm algorithm;
int max_cost;
/* synth_mult does an `unsigned int' multiply. As long as the mode is
less than or equal in size to `unsigned int' this doesn't matter.
If the mode is larger than `unsigned int', then synth_mult works only
if the constant value exactly fits in an `unsigned int' without any
truncation. This means that multiplying by negative values does
not work; results are off by 2^32 on a 32 bit machine. */
/* Handling const0_rtx here allows us to use zero as a rogue value for
coeff below. */
if (op1 == const0_rtx)
return const0_rtx;
if (op1 == const1_rtx)
return op0;
if (op1 == constm1_rtx)
return expand_unop (mode,
GET_MODE_CLASS (mode) == MODE_INT
&& !unsignedp && flag_trapv
? negv_optab : neg_optab,
op0, target, 0);
/* If we are multiplying in DImode, it may still be a win
to try to work with shifts and adds. */
if (GET_CODE (op1) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (op1)) == MODE_INT
&& HOST_BITS_PER_INT >= BITS_PER_WORD
&& CONST_DOUBLE_HIGH (op1) == 0)
const_op1 = GEN_INT (CONST_DOUBLE_LOW (op1));
else if (HOST_BITS_PER_INT < GET_MODE_BITSIZE (mode)
&& GET_CODE (op1) == CONST_INT
&& INTVAL (op1) < 0)
const_op1 = 0;
/* We used to test optimize here, on the grounds that it's better to
produce a smaller program when -O is not used.
But this causes such a terrible slowdown sometimes
that it seems better to use synth_mult always. */
if (const_op1 && GET_CODE (const_op1) == CONST_INT
/* These are the operations that are potentially turned into a sequence
of shifts and additions. */
if (GET_MODE_CLASS (mode) == MODE_INT
&& (unsignedp || !flag_trapv))
{
HOST_WIDE_INT coeff = INTVAL (const_op1);
int mult_cost;
HOST_WIDE_INT coeff = 0;
/* Special case powers of two. */
if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
/* synth_mult does an `unsigned int' multiply. As long as the mode is
less than or equal in size to `unsigned int' this doesn't matter.
If the mode is larger than `unsigned int', then synth_mult works
only if the constant value exactly fits in an `unsigned int' without
any truncation. This means that multiplying by negative values does
not work; results are off by 2^32 on a 32 bit machine. */
if (GET_CODE (op1) == CONST_INT)
{
if (coeff == 0)
return const0_rtx;
if (coeff == 1)
return op0;
return expand_shift (LSHIFT_EXPR, mode, op0,
build_int_cst (NULL_TREE, floor_log2 (coeff)),
target, unsignedp);
/* Attempt to handle multiplication of DImode values by negative
coefficients, by performing the multiplication by a positive
multiplier and then inverting the result. */
if (INTVAL (op1) < 0
&& GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
{
/* Its safe to use -INTVAL (op1) even for INT_MIN, as the
result is interpreted as an unsigned coefficient. */
max_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET)
- neg_cost[mode];
if (max_cost > 0
&& choose_mult_variant (mode, -INTVAL (op1), &algorithm,
&variant, max_cost))
{
rtx temp = expand_mult_const (mode, op0, -INTVAL (op1),
NULL_RTX, &algorithm,
variant);
return expand_unop (mode, neg_optab, temp, target, 0);
}
}
else coeff = INTVAL (op1);
}
else if (GET_CODE (op1) == CONST_DOUBLE)
{
/* If we are multiplying in DImode, it may still be a win
to try to work with shifts and adds. */
if (CONST_DOUBLE_HIGH (op1) == 0)
coeff = CONST_DOUBLE_LOW (op1);
else if (CONST_DOUBLE_LOW (op1) == 0
&& EXACT_POWER_OF_2_OR_ZERO_P (CONST_DOUBLE_HIGH (op1)))
{
int shift = floor_log2 (CONST_DOUBLE_HIGH (op1))
+ HOST_BITS_PER_WIDE_INT;
return expand_shift (LSHIFT_EXPR, mode, op0,
build_int_cst (NULL_TREE, shift),
target, unsignedp);
}
}
/* We used to test optimize here, on the grounds that it's better to
produce a smaller program when -O is not used. But this causes
such a terrible slowdown sometimes that it seems better to always
use synth_mult. */
if (coeff != 0)
{
/* Special case powers of two. */
if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
return expand_shift (LSHIFT_EXPR, mode, op0,
build_int_cst (NULL_TREE, floor_log2 (coeff)),
target, unsignedp);
mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
if (choose_mult_variant (mode, coeff, &algorithm, &variant,
mult_cost))
return expand_mult_const (mode, op0, coeff, target,
&algorithm, variant);
max_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
if (choose_mult_variant (mode, coeff, &algorithm, &variant,
max_cost))
return expand_mult_const (mode, op0, coeff, target,
&algorithm, variant);
}
}
if (GET_CODE (op0) == CONST_DOUBLE)