aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRoger Sayle <roger@eyesopen.com>2004-06-29 17:13:08 +0000
committerRoger Sayle <sayle@gcc.gnu.org>2004-06-29 17:13:08 +0000
commit1c234fcb7273f09aa3cb32274c58e7c2ed0abcb3 (patch)
tree3526890960c85ad4ae1680858ad18c224437b6fc /gcc
parente1514303f2550329accaf2fe3b7eec9ca54f9724 (diff)
downloadgcc-1c234fcb7273f09aa3cb32274c58e7c2ed0abcb3.zip
gcc-1c234fcb7273f09aa3cb32274c58e7c2ed0abcb3.tar.gz
gcc-1c234fcb7273f09aa3cb32274c58e7c2ed0abcb3.tar.bz2
expmed.c (expand_smod_pow2): Provide alternate implementations that avoid conditional jumps...
* expmed.c (expand_smod_pow2): Provide alternate implementations that avoid conditional jumps, and choose between them based upon the target's rtx_costs. From-SVN: r83861
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/expmed.c47
2 files changed, 42 insertions, 11 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 59f35c1..36fedf6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2004-06-29 Roger Sayle <roger@eyesopen.com>
+
+ * expmed.c (expand_smod_pow2): Provide alternate implementations
+ that avoid conditional jumps, and choose between them based upon
+ the target's rtx_costs.
+
2004-06-29 Andrew Pinski <apinski@apple.com>
* tree-sra.c: Include expr.h for definition of MOVE_RATIO.
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 6316f99..bb60ba1 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -3064,7 +3064,7 @@ static rtx
expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
{
unsigned HOST_WIDE_INT mask;
- rtx result, temp, label;
+ rtx result, temp, shift, label;
int logd;
logd = floor_log2 (d);
@@ -3079,17 +3079,42 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
if (signmask)
{
signmask = force_reg (mode, signmask);
- temp = expand_binop (mode, xor_optab, op0, signmask,
- NULL_RTX, 1, OPTAB_LIB_WIDEN);
- temp = expand_binop (mode, sub_optab, temp, signmask,
- NULL_RTX, 0, OPTAB_LIB_WIDEN);
mask = ((HOST_WIDE_INT) 1 << logd) - 1;
- temp = expand_binop (mode, and_optab, temp, GEN_INT (mask),
- NULL_RTX, 1, OPTAB_LIB_WIDEN);
- temp = expand_binop (mode, xor_optab, temp, signmask,
- NULL_RTX, 1, OPTAB_LIB_WIDEN);
- temp = expand_binop (mode, sub_optab, temp, signmask,
- NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
+
+ /* Use the rtx_cost of a LSHIFTRT instruction to determine
+ which instruction sequence to use. If logical right shifts
+ are expensive the use 2 XORs, 2 SUBs and an AND, otherwise
+ use a LSHIFTRT, 1 ADD, 1 SUB and an AND. */
+
+ temp = gen_rtx_LSHIFTRT (mode, result, shift);
+ if (lshr_optab->handlers[mode].insn_code == CODE_FOR_nothing
+ || rtx_cost (temp, SET) > COSTS_N_INSNS (2))
+ {
+ temp = expand_binop (mode, xor_optab, op0, signmask,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ temp = expand_binop (mode, sub_optab, temp, signmask,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ temp = expand_binop (mode, and_optab, temp, GEN_INT (mask),
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ temp = expand_binop (mode, xor_optab, temp, signmask,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ temp = expand_binop (mode, sub_optab, temp, signmask,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ }
+ else
+ {
+ signmask = expand_binop (mode, lshr_optab, signmask, shift,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ signmask = force_reg (mode, signmask);
+
+ temp = expand_binop (mode, add_optab, op0, signmask,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ temp = expand_binop (mode, and_optab, temp, GEN_INT (mask),
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ temp = expand_binop (mode, sub_optab, temp, signmask,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ }
return temp;
}
}