Commit 39cab019 by Roger Sayle Committed by Roger Sayle

expmed.c (expand_sdiv_pow2): New function to expand signed division by a positive power of two...


	* expmed.c (expand_sdiv_pow2): New function to expand signed division
	by a positive power of two, split out from expand_divmod.  Provide
	an alternate implementation when shifts are expensive.  Lower the
	threshold for using a branchless implementation to BRANCH_COST >= 2.
	(expand_divmod): Call expand_sdiv_pow2 for suitable divisions.

From-SVN: r84686
parent 51a61243
2004-07-14 Roger Sayle <roger@eyesopen.com>
* expmed.c (expand_sdiv_pow2): New function to expand signed division
by a positive power of two, split out from expand_divmod. Provide
an alternate implementation when shifts are expensive. Lower the
threshold for using a branchless implementation to BRANCH_COST >= 2.
(expand_divmod): Call expand_sdiv_pow2 for suitable divisions.
2004-07-14 Paolo Bonzini <bonzini@gnu.org> 2004-07-14 Paolo Bonzini <bonzini@gnu.org>
* tree-dfa.c (make_rename_temp): *Really* work just * tree-dfa.c (make_rename_temp): *Really* work just
......
...@@ -52,6 +52,7 @@ static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT, ...@@ -52,6 +52,7 @@ static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, int); unsigned HOST_WIDE_INT, int);
static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx); static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx);
static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT); static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
/* Nonzero means divides or modulus operations are relatively cheap for /* Nonzero means divides or modulus operations are relatively cheap for
powers of two, so don't use branches; emit the operation instead. powers of two, so don't use branches; emit the operation instead.
...@@ -3170,6 +3171,53 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d) ...@@ -3170,6 +3171,53 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
emit_label (label); emit_label (label);
return result; return result;
} }
/* Expand signed division of OP0 by a power of two D in mode MODE.
This routine is only called for positive values of D. */
static rtx
expand_sdiv_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
{
rtx temp, label;
tree shift;
int logd;
logd = floor_log2 (d);
shift = build_int_2 (logd, 0);
if (d == 2 && BRANCH_COST >= 1)
{
temp = gen_reg_rtx (mode);
temp = emit_store_flag (temp, LT, op0, const0_rtx, mode, 0, 1);
temp = expand_binop (mode, add_optab, temp, op0, NULL_RTX,
0, OPTAB_LIB_WIDEN);
return expand_shift (RSHIFT_EXPR, mode, temp, shift, NULL_RTX, 0);
}
if (BRANCH_COST >= 2)
{
int ushift = GET_MODE_BITSIZE (mode) - logd;
temp = gen_reg_rtx (mode);
temp = emit_store_flag (temp, LT, op0, const0_rtx, mode, 0, -1);
if (shift_cost[mode][ushift] > COSTS_N_INSNS (1))
temp = expand_binop (mode, and_optab, temp, GEN_INT (d - 1),
NULL_RTX, 0, OPTAB_LIB_WIDEN);
else
temp = expand_shift (RSHIFT_EXPR, mode, temp,
build_int_2 (ushift, 0), NULL_RTX, 1);
temp = expand_binop (mode, add_optab, temp, op0, NULL_RTX,
0, OPTAB_LIB_WIDEN);
return expand_shift (RSHIFT_EXPR, mode, temp, shift, NULL_RTX, 0);
}
label = gen_label_rtx ();
temp = copy_to_mode_reg (mode, op0);
do_cmp_and_jump (temp, const0_rtx, GE, mode, label);
expand_inc (temp, GEN_INT (d - 1));
emit_label (label);
return expand_shift (RSHIFT_EXPR, mode, temp, shift, NULL_RTX, 0);
}
/* Emit the code to divide OP0 by OP1, putting the result in TARGET /* Emit the code to divide OP0 by OP1, putting the result in TARGET
if that is convenient, and returning where the result is. if that is convenient, and returning where the result is.
...@@ -3582,38 +3630,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode, ...@@ -3582,38 +3630,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
if (remainder) if (remainder)
return gen_lowpart (mode, remainder); return gen_lowpart (mode, remainder);
} }
lgup = floor_log2 (abs_d); quotient = expand_sdiv_pow2 (compute_mode, op0, abs_d);
if (BRANCH_COST < 1 || (abs_d != 2 && BRANCH_COST < 3))
{
rtx label = gen_label_rtx ();
rtx t1;
t1 = copy_to_mode_reg (compute_mode, op0);
do_cmp_and_jump (t1, const0_rtx, GE,
compute_mode, label);
expand_inc (t1, gen_int_mode (abs_d - 1,
compute_mode));
emit_label (label);
quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1,
build_int_2 (lgup, 0),
tquotient, 0);
}
else
{
rtx t1, t2, t3;
t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
build_int_2 (size - 1, 0),
NULL_RTX, 0);
t2 = expand_shift (RSHIFT_EXPR, compute_mode, t1,
build_int_2 (size - lgup, 0),
NULL_RTX, 1);
t3 = force_operand (gen_rtx_PLUS (compute_mode,
op0, t2),
NULL_RTX);
quotient = expand_shift (RSHIFT_EXPR, compute_mode, t3,
build_int_2 (lgup, 0),
tquotient, 0);
}
/* We have computed OP0 / abs(OP1). If OP1 is negative, /* We have computed OP0 / abs(OP1). If OP1 is negative,
negate the quotient. */ negate the quotient. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment