aboutsummaryrefslogtreecommitdiff
path: root/gcc/expmed.c
diff options
context:
space:
mode:
authorTom Wood <wood@gnu.org>1992-07-25 10:14:05 +0000
committerTom Wood <wood@gnu.org>1992-07-25 10:14:05 +0000
commit3d32ffd13f07496796ce687a276ccea34a96ae70 (patch)
treede4be488decee1b41097f56119290f5340ff1996 /gcc/expmed.c
parent3a6aca8e65b3096c59bef64888ef6f54a94606e3 (diff)
downloadgcc-3d32ffd13f07496796ce687a276ccea34a96ae70.zip
gcc-3d32ffd13f07496796ce687a276ccea34a96ae70.tar.gz
gcc-3d32ffd13f07496796ce687a276ccea34a96ae70.tar.bz2
(expand_divmod): Eliminate the generation of branches
when possible. From-SVN: r1687
Diffstat (limited to 'gcc/expmed.c')
-rw-r--r--gcc/expmed.c66
1 files changed, 54 insertions, 12 deletions
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 94878d1..5b6ed4d 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -2156,6 +2156,12 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
rtx adjusted_op0 = op0;
optab optab1, optab2;
+ /* We shouldn't be called with op1 == const1_rtx, but some of the
+ code below will malfunction if we are, so check here and handle
+ the special case if so. */
+ if (op1 == const1_rtx)
+ return rem_flag ? const0_rtx : op0;
+
/* Don't use the function value register as a target
since we have to read it as well as write it,
and function-inlining gets confused by this. */
@@ -2273,7 +2279,6 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
case TRUNC_DIV_EXPR:
if (log >= 0 && ! unsignedp)
{
- rtx label = gen_label_rtx ();
if (! can_clobber_op0)
{
adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target,
@@ -2282,11 +2287,32 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
which will screw up mem refs for autoincrements. */
op0 = force_reg (compute_mode, op0);
}
- emit_cmp_insn (adjusted_op0, const0_rtx, GE,
- NULL_RTX, compute_mode, 0, 0);
- emit_jump_insn (gen_bge (label));
- expand_inc (adjusted_op0, plus_constant (op1, -1));
- emit_label (label);
+ /* Here we need to add OP1-1 if OP0 is negative, 0 otherwise.
+ This can be computed without jumps by arithmetically shifting
+ OP0 right LOG-1 places and then shifting right logically
+ SIZE-LOG bits. The resulting value is unconditionally added
+ to OP0. */
+ if (log == 1 || BRANCH_COST >= 3)
+ {
+ rtx temp = gen_reg_rtx (compute_mode);
+ temp = copy_to_suggested_reg (adjusted_op0, temp, compute_mode);
+ temp = expand_shift (RSHIFT_EXPR, compute_mode, temp,
+ build_int_2 (log - 1, 0), NULL_RTX, 0);
+ temp = expand_shift (RSHIFT_EXPR, compute_mode, temp,
+ build_int_2 (GET_MODE_BITSIZE (mode) - log,
+ 0),
+ temp, 1);
+ expand_inc (adjusted_op0, temp);
+ }
+ else
+ {
+ rtx label = gen_label_rtx ();
+ emit_cmp_insn (adjusted_op0, const0_rtx, GE,
+ NULL_RTX, compute_mode, 0, 0);
+ emit_jump_insn (gen_bge (label));
+ expand_inc (adjusted_op0, plus_constant (op1, -1));
+ emit_label (label);
+ }
mod_insn_no_good = 1;
}
break;
@@ -2364,12 +2390,28 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
integer_one_node, NULL_RTX, 0);
if (! unsignedp)
{
- rtx label = gen_label_rtx ();
- emit_cmp_insn (adjusted_op0, const0_rtx, GE, NULL_RTX,
- compute_mode, 0, 0);
- emit_jump_insn (gen_bge (label));
- expand_unop (compute_mode, neg_optab, op1, op1, 0);
- emit_label (label);
+ if (BRANCH_COST >= 2)
+ {
+ /* Negate OP1 if OP0 < 0. Do this by computing a temporary
+ that has all bits equal to the sign bit and exclusive
+ or-ing it with OP1. */
+ rtx temp = gen_reg_rtx (compute_mode);
+ temp = copy_to_suggested_reg (adjusted_op0, temp, compute_mode);
+ temp = expand_shift (RSHIFT_EXPR, compute_mode, temp,
+ build_int_2 (GET_MODE_BITSIZE (mode) - 1, 0),
+ NULL_RTX, 0);
+ op1 = expand_binop (compute_mode, xor_optab, op1, temp, op1,
+ unsignedp, OPTAB_LIB_WIDEN);
+ }
+ else
+ {
+ rtx label = gen_label_rtx ();
+ emit_cmp_insn (adjusted_op0, const0_rtx, GE, NULL_RTX,
+ compute_mode, 0, 0);
+ emit_jump_insn (gen_bge (label));
+ expand_unop (compute_mode, neg_optab, op1, op1, 0);
+ emit_label (label);
+ }
}
expand_inc (adjusted_op0, op1);
}