(expand_divmod, case ROUND_DIV_EXPR): Implement.
authorRichard Kenner <kenner@gcc.gnu.org>
Tue, 15 Nov 1994 21:50:23 +0000 (16:50 -0500)
committerRichard Kenner <kenner@gcc.gnu.org>
Tue, 15 Nov 1994 21:50:23 +0000 (16:50 -0500)
From-SVN: r8442

gcc/expmed.c

index bae088d223a64c11218159f69696f01601cbfa50..6c60f6a6b9c9663b11441a45e0b104eb728fff08 100644 (file)
@@ -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)