Commit 0b55e932 by Roger Sayle Committed by Roger Sayle

expmed.c (expand_smod_pow2): New function to expand signed remainder by a…

expmed.c (expand_smod_pow2): New function to expand signed remainder by a constant power of 2, such as "x % 16".


	* expmed.c (expand_smod_pow2): New function to expand signed
	remainder by a constant power of 2, such as "x % 16".
	(expand_divmod): Call new expand_smod_pow2 when appropriate.
	Minor corrections to comments, e.g. wrapping long lines.

From-SVN: r83815
parent 3b50d22e
2004-06-28 Roger Sayle <roger@eyesopen.com>
* expmed.c (expand_smod_pow2): New function to expand signed
remainder by a constant power of 2, such as "x % 16".
(expand_divmod): Call new expand_smod_pow2 when appropriate.
Minor corrections to comments, e.g. wrapping long lines.
2004-06-28 Ulrich Weigand <uweigand@de.ibm.com> 2004-06-28 Ulrich Weigand <uweigand@de.ibm.com>
* Makefile.in (vec.o): Fix dependencies. * Makefile.in (vec.o): Fix dependencies.
......
...@@ -51,6 +51,7 @@ static rtx lshift_value (enum machine_mode, rtx, int, int); ...@@ -51,6 +51,7 @@ static rtx lshift_value (enum machine_mode, rtx, int, int);
static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT, 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);
/* 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.
...@@ -3055,6 +3056,72 @@ expand_mult_highpart (enum machine_mode mode, rtx op0, ...@@ -3055,6 +3056,72 @@ expand_mult_highpart (enum machine_mode mode, rtx op0,
return expand_mult_highpart_optab (mode, op0, op1, target, return expand_mult_highpart_optab (mode, op0, op1, target,
unsignedp, max_cost); unsignedp, max_cost);
} }
/* Expand signed modulus of OP0 by a power of two D in mode MODE. */
static rtx
expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
{
unsigned HOST_WIDE_INT mask;
rtx result, temp, label;
int logd;
logd = floor_log2 (d);
result = gen_reg_rtx (mode);
/* Avoid conditional branches when they're expensive. */
if (BRANCH_COST >= 2
&& !optimize_size)
{
rtx signmask = emit_store_flag (result, LT, op0, const0_rtx,
mode, 0, -1);
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);
return temp;
}
}
/* Mask contains the mode's signbit and the significant bits of the
modulus. By including the signbit in the operation, many targets
can avoid an explicit compare operation in the following comparison
against zero. */
mask = (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)
| (((HOST_WIDE_INT) 1 << logd) - 1);
temp = expand_binop (mode, and_optab, op0, GEN_INT (mask), result,
1, OPTAB_LIB_WIDEN);
if (temp != result)
emit_move_insn (result, temp);
label = gen_label_rtx ();
do_cmp_and_jump (result, const0_rtx, GE, mode, label);
temp = expand_binop (mode, sub_optab, result, const1_rtx, result,
0, OPTAB_LIB_WIDEN);
mask = (HOST_WIDE_INT) -1 << logd;
temp = expand_binop (mode, ior_optab, temp, GEN_INT (mask), result,
1, OPTAB_LIB_WIDEN);
temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
0, OPTAB_LIB_WIDEN);
if (temp != result)
emit_move_insn (result, temp);
emit_label (label);
return result;
}
/* 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.
...@@ -3451,10 +3518,8 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode, ...@@ -3451,10 +3518,8 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
else if (EXACT_POWER_OF_2_OR_ZERO_P (d) else if (EXACT_POWER_OF_2_OR_ZERO_P (d)
&& (rem_flag ? smod_pow2_cheap[compute_mode] && (rem_flag ? smod_pow2_cheap[compute_mode]
: sdiv_pow2_cheap[compute_mode]) : sdiv_pow2_cheap[compute_mode])
/* ??? The cheap metric is computed only for /* We assume that cheap metric is true if the
word_mode. If this operation is wider, this may optab has an expander for this mode. */
not be so. Assume true if the optab has an
expander for this mode. */
&& (((rem_flag ? smod_optab : sdiv_optab) && (((rem_flag ? smod_optab : sdiv_optab)
->handlers[compute_mode].insn_code ->handlers[compute_mode].insn_code
!= CODE_FOR_nothing) != CODE_FOR_nothing)
...@@ -3463,6 +3528,12 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode, ...@@ -3463,6 +3528,12 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
; ;
else if (EXACT_POWER_OF_2_OR_ZERO_P (abs_d)) else if (EXACT_POWER_OF_2_OR_ZERO_P (abs_d))
{ {
if (rem_flag)
{
remainder = expand_smod_pow2 (compute_mode, op0, d);
if (remainder)
return gen_lowpart (mode, remainder);
}
lgup = floor_log2 (abs_d); lgup = floor_log2 (abs_d);
if (BRANCH_COST < 1 || (abs_d != 2 && BRANCH_COST < 3)) if (BRANCH_COST < 1 || (abs_d != 2 && BRANCH_COST < 3))
{ {
...@@ -3496,8 +3567,8 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode, ...@@ -3496,8 +3567,8 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
tquotient, 0); tquotient, 0);
} }
/* We have computed OP0 / abs(OP1). If OP1 is negative, negate /* We have computed OP0 / abs(OP1). If OP1 is negative,
the quotient. */ negate the quotient. */
if (d < 0) if (d < 0)
{ {
insn = get_last_insn (); insn = get_last_insn ();
......
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