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:
parent
92c54d2c4e
commit
65dc935013
@ -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
|
||||
|
121
gcc/expmed.c
121
gcc/expmed.c
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user