From: Richard Kenner Date: Tue, 15 Nov 1994 21:50:23 +0000 (-0500) Subject: (expand_divmod, case ROUND_DIV_EXPR): Implement. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=69f619018a585979500e0e80d3d106aaf3b62820;p=gcc.git (expand_divmod, case ROUND_DIV_EXPR): Implement. From-SVN: r8442 --- diff --git a/gcc/expmed.c b/gcc/expmed.c index bae088d223a..6c60f6a6b9c 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)