summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorsayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>2005-03-13 17:06:42 +0000
committersayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4>2005-03-13 17:06:42 +0000
commitcfd6d9853aea7481ab5746dada65c9e7fe9cce9e (patch)
treee4f79f782ea00652a790b8ec5f90102f92e7c5d1 /gcc
parentd931305e795bfba310e1f220f645ab811659ce84 (diff)
downloadgcc-cfd6d9853aea7481ab5746dada65c9e7fe9cce9e.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@96377 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/expmed.c125
2 files changed, 90 insertions, 43 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1a9614f6334..f3a66255d94 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/expmed.c b/gcc/expmed.c
index afbbaf53869..093791e148a 100644
--- a/gcc/expmed.c
+++ b/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. */
-
- /* 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
+ /* 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);
+
+ /* 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);
+
+ 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)