diff options
author | sayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-03-13 17:06:42 +0000 |
---|---|---|
committer | sayle <sayle@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-03-13 17:06:42 +0000 |
commit | cfd6d9853aea7481ab5746dada65c9e7fe9cce9e (patch) | |
tree | e4f79f782ea00652a790b8ec5f90102f92e7c5d1 /gcc | |
parent | d931305e795bfba310e1f220f645ab811659ce84 (diff) | |
download | gcc-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/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/expmed.c | 125 |
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) |