aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Kenner <kenner@gcc.gnu.org>1994-11-15 16:50:23 -0500
committerRichard Kenner <kenner@gcc.gnu.org>1994-11-15 16:50:23 -0500
commit69f619018a585979500e0e80d3d106aaf3b62820 (patch)
tree11d366944335943467490654830ef4440ff6a7e2 /gcc
parent923f781d832a9ac82e0013d035a7b7afb108f6ff (diff)
downloadgcc-69f619018a585979500e0e80d3d106aaf3b62820.zip
gcc-69f619018a585979500e0e80d3d106aaf3b62820.tar.gz
gcc-69f619018a585979500e0e80d3d106aaf3b62820.tar.bz2
(expand_divmod, case ROUND_DIV_EXPR): Implement.
From-SVN: r8442
Diffstat (limited to 'gcc')
-rw-r--r--gcc/expmed.c76
1 files changed, 68 insertions, 8 deletions
diff --git a/gcc/expmed.c b/gcc/expmed.c
index bae088d..6c60f6a 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -2608,13 +2608,13 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
Second comes a switch statement with code specific for each rounding mode.
For some special operands this code emits all RTL for the desired
- operation, for other cases, it generates a quotient and stores it in
+ operation, for other cases, it generates only a quotient and stores it in
QUOTIENT. The case for trunc division/remainder might leave quotient = 0,
to indicate that it has not done anything.
- Last comes code that finishes the operation. If QUOTIENT is set an
- REM_FLAG, the remainder is computed as OP0 - QUOTIENT * OP1. If QUOTIENT
- is not set, it is computed using trunc rounding.
+ Last comes code that finishes the operation. If QUOTIENT is set and
+ REM_FLAG is set, the remainder is computed as OP0 - QUOTIENT * OP1. If
+ QUOTIENT is not set, it is computed using trunc rounding.
We try to generate special code for division and remainder when OP1 is a
constant. If |OP1| = 2**n we can use shifts and some other fast
@@ -3408,10 +3408,70 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
case ROUND_DIV_EXPR:
case ROUND_MOD_EXPR:
- /* The code that used to be here was wrong, and nothing really
- depends on it. */
- abort ();
- break;
+ if (unsignedp)
+ {
+ rtx tem;
+ rtx label;
+ label = gen_label_rtx ();
+ quotient = gen_reg_rtx (compute_mode);
+ remainder = gen_reg_rtx (compute_mode);
+ if (expand_twoval_binop (udivmod_optab, op0, op1, quotient, remainder, 1) == 0)
+ {
+ rtx tem;
+ quotient = expand_binop (compute_mode, udiv_optab, op0, op1,
+ quotient, 1, OPTAB_LIB_WIDEN);
+ tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 1);
+ remainder = expand_binop (compute_mode, sub_optab, op0, tem,
+ remainder, 1, OPTAB_LIB_WIDEN);
+ }
+ tem = plus_constant (op1, -1);
+ tem = expand_shift (RSHIFT_EXPR, compute_mode, tem,
+ build_int_2 (1, 0), NULL_RTX, 1);
+ emit_cmp_insn (remainder, tem, LEU, NULL_RTX, compute_mode, 0, 0);
+ emit_jump_insn (gen_bleu (label));
+ expand_inc (quotient, const1_rtx);
+ expand_dec (remainder, op1);
+ emit_label (label);
+ }
+ else
+ {
+ rtx abs_rem, abs_op1, tem, mask;
+ rtx label;
+ label = gen_label_rtx ();
+ quotient = gen_reg_rtx (compute_mode);
+ remainder = gen_reg_rtx (compute_mode);
+ if (expand_twoval_binop (sdivmod_optab, op0, op1, quotient, remainder, 0) == 0)
+ {
+ rtx tem;
+ quotient = expand_binop (compute_mode, sdiv_optab, op0, op1,
+ quotient, 0, OPTAB_LIB_WIDEN);
+ tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 0);
+ remainder = expand_binop (compute_mode, sub_optab, op0, tem,
+ remainder, 0, OPTAB_LIB_WIDEN);
+ }
+ abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 0, 0);
+ abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 0, 0);
+ tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem,
+ build_int_2 (1, 0), NULL_RTX, 1);
+ emit_cmp_insn (tem, abs_op1, LTU, NULL_RTX, compute_mode, 0, 0);
+ emit_jump_insn (gen_bltu (label));
+ tem = expand_binop (compute_mode, xor_optab, op0, op1,
+ NULL_RTX, 0, OPTAB_WIDEN);
+ mask = expand_shift (RSHIFT_EXPR, compute_mode, tem,
+ build_int_2 (size - 1, 0), NULL_RTX, 0);
+ tem = expand_binop (compute_mode, xor_optab, mask, const1_rtx,
+ NULL_RTX, 0, OPTAB_WIDEN);
+ tem = expand_binop (compute_mode, sub_optab, tem, mask,
+ NULL_RTX, 0, OPTAB_WIDEN);
+ expand_inc (quotient, tem);
+ tem = expand_binop (compute_mode, xor_optab, mask, op1,
+ NULL_RTX, 0, OPTAB_WIDEN);
+ tem = expand_binop (compute_mode, sub_optab, tem, mask,
+ NULL_RTX, 0, OPTAB_WIDEN);
+ expand_dec (remainder, tem);
+ emit_label (label);
+ }
+ return gen_lowpart (mode, rem_flag ? remainder : quotient);
}
if (quotient == 0)