Commit 65dc9350 by Roger Sayle Committed by Roger Sayle

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
parent 92c54d2c
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> 2005-03-13 Kazu Hirata <kazu@cs.umass.edu>
* tree-into-ssa.c (find_idf): Speed up by putting the indexes * tree-into-ssa.c (find_idf): Speed up by putting the indexes
......
...@@ -3011,57 +3011,96 @@ rtx ...@@ -3011,57 +3011,96 @@ rtx
expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target, expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
int unsignedp) int unsignedp)
{ {
rtx const_op1 = op1;
enum mult_variant variant; enum mult_variant variant;
struct algorithm algorithm; struct algorithm algorithm;
int max_cost;
/* synth_mult does an `unsigned int' multiply. As long as the mode is /* Handling const0_rtx here allows us to use zero as a rogue value for
less than or equal in size to `unsigned int' this doesn't matter. coeff below. */
If the mode is larger than `unsigned int', then synth_mult works only if (op1 == const0_rtx)
if the constant value exactly fits in an `unsigned int' without any return const0_rtx;
truncation. This means that multiplying by negative values does if (op1 == const1_rtx)
not work; results are off by 2^32 on a 32 bit machine. */ return op0;
if (op1 == constm1_rtx)
/* If we are multiplying in DImode, it may still be a win return expand_unop (mode,
to try to work with shifts and adds. */ GET_MODE_CLASS (mode) == MODE_INT
if (GET_CODE (op1) == CONST_DOUBLE && !unsignedp && flag_trapv
&& GET_MODE_CLASS (GET_MODE (op1)) == MODE_INT ? negv_optab : neg_optab,
&& HOST_BITS_PER_INT >= BITS_PER_WORD op0, target, 0);
&& CONST_DOUBLE_HIGH (op1) == 0)
const_op1 = GEN_INT (CONST_DOUBLE_LOW (op1)); /* These are the operations that are potentially turned into a sequence
else if (HOST_BITS_PER_INT < GET_MODE_BITSIZE (mode) of shifts and additions. */
&& GET_CODE (op1) == CONST_INT if (GET_MODE_CLASS (mode) == MODE_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
&& (unsignedp || !flag_trapv)) && (unsignedp || !flag_trapv))
{ {
HOST_WIDE_INT coeff = INTVAL (const_op1); HOST_WIDE_INT coeff = 0;
int mult_cost;
/* Special case powers of two. */ /* synth_mult does an `unsigned int' multiply. As long as the mode is
if (EXACT_POWER_OF_2_OR_ZERO_P (coeff)) 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) /* Attempt to handle multiplication of DImode values by negative
return const0_rtx; coefficients, by performing the multiplication by a positive
if (coeff == 1) multiplier and then inverting the result. */
return op0; if (INTVAL (op1) < 0
return expand_shift (LSHIFT_EXPR, mode, op0, && GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
build_int_cst (NULL_TREE, floor_log2 (coeff)), {
target, unsignedp); /* 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);
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);
} }
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);
} }
if (GET_CODE (op0) == CONST_DOUBLE) if (GET_CODE (op0) == CONST_DOUBLE)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment