Date: Mon, 13 Apr 1998 11:52:42 +1000 (EST) From: Peter Jeremy <Peter.Jeremy@alcatel.com.au> To: bug-gcc@prep.ai.mit.edu Cc: freebsd-ports@FreeBSD.ORG Subject: gcc2.8.1 divide-by-constant optimisation causes call to __cmpdi2 Message-ID: <199804130152.LAA00492@gsms01.alcatel.com.au>
next in thread | raw e-mail | index | archive | help
gcc version 2.8.1 for i386-unknown-freebsd2.2.5 and sparc-sun-solaris2.5 Sample input file (testcase.i): --- int test_int_ll(long long val) { return (val / 256); } --- Compile in the gcc build directory using: ./cc1 testcase.i -g The problem is not affected by the use of -O2. Compiler was configured on a FreeBSD 2.2.5R system using `./configure' using the standard gcc 2.8.0 + 2.8.0->2.8.1 patches. Compiler was configured on a Solaris 2.5.1 system in a subdirectory of gcc-2.8.1 using `../configure --with-gnu-ld --with-gnu-as --build=sparc-sun-solaris2.5'. The compiler recognizes the use of a power-of-2 constant as the denominator in the above division and expands it inline to a shift. This requires special handling for negative numerators and so the expanded code includes a comparison. In the case of long long division, the comparison is not explicitly open-coded (unlike the relational comparison expansions). The problem is fixed for FreeBSD using the following patch. This patch has not been tested on Solaris 2.x: -- *** ChangeLog~ Sat Mar 28 08:03:41 1998 --- ChangeLog Sat Apr 11 09:09:50 1998 *************** *** 1,3 **** --- 1,14 ---- + Sat Apr 11 08:56:35 1998 Peter Jeremy <peter.jeremy@alcatel.com.au> + + * expr.c (do_jump_by_parts_equality_rtx): Make function public + so it can be referenced from expmed.c. + + * expmed.c (do_cmp_and_jump): New function based on multi-word + comparison handling in expr.c:do_jump(). + + * expmed.c (expand_divmod): convert emit_cmp_insn/emit_jump_insn + sequences to do_cmp_and_jump so multi-word modes are in-lined. + Mon Mar 2 08:06:58 1998 Richard Kenner <kenner@vlsi1.ultra.nyu.edu> * Version 2.8.1 released. *** expmed.c~ Sun Nov 9 09:11:58 1997 --- expmed.c Sat Apr 11 09:15:53 1998 *************** static rtx mask_rtx PROTO((enum machin *** 41,46 **** --- 41,48 ---- static rtx lshift_value PROTO((enum machine_mode, rtx, int, int)); static rtx extract_split_bit_field PROTO((rtx, int, int, int, int)); + static void do_cmp_and_jump PROTO((rtx, rtx, enum rtx_code, + enum machine_mode, rtx)); #define CEIL(x,y) (((x) + (y) - 1) / (y)) *************** expand_divmod (rem_flag, code, mode, op0 *** 3027,3035 **** rtx t1; t1 = copy_to_mode_reg (compute_mode, op0); ! emit_cmp_insn (t1, const0_rtx, GE, ! NULL_RTX, compute_mode, 0, 0); ! emit_jump_insn (gen_bge (label)); expand_inc (t1, GEN_INT (abs_d - 1)); emit_label (label); quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1, --- 3029,3036 ---- 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 (abs_d - 1)); emit_label (label); quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1, *************** expand_divmod (rem_flag, code, mode, op0 *** 3255,3267 **** Save that for later. */ rtx tem; rtx label = gen_label_rtx (); ! emit_cmp_insn (remainder, const0_rtx, EQ, NULL_RTX, ! compute_mode, 0, 0); ! emit_jump_insn (gen_beq (label)); tem = expand_binop (compute_mode, xor_optab, op0, op1, NULL_RTX, 0, OPTAB_WIDEN); ! emit_cmp_insn (tem, const0_rtx, GE, NULL_RTX, compute_mode, 0, 0); ! emit_jump_insn (gen_bge (label)); expand_dec (quotient, const1_rtx); expand_inc (remainder, op1); emit_label (label); --- 3256,3265 ---- Save that for later. */ rtx tem; rtx label = gen_label_rtx (); ! do_cmp_and_jump (remainder, const0_rtx, EQ, compute_mode, label); tem = expand_binop (compute_mode, xor_optab, op0, op1, NULL_RTX, 0, OPTAB_WIDEN); ! do_cmp_and_jump (tem, const0_rtx, GE, compute_mode, label); expand_dec (quotient, const1_rtx); expand_inc (remainder, op1); emit_label (label); *************** expand_divmod (rem_flag, code, mode, op0 *** 3282,3292 **** label3 = gen_label_rtx (); label4 = gen_label_rtx (); label5 = gen_label_rtx (); ! emit_cmp_insn (op1, const0_rtx, LT, NULL_RTX, compute_mode, 0, 0); emit_jump_insn (gen_blt (label2)); ! emit_cmp_insn (adjusted_op0, const0_rtx, LT, NULL_RTX, ! compute_mode, 0, 0); ! emit_jump_insn (gen_blt (label1)); tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1, quotient, 0, OPTAB_LIB_WIDEN); if (tem != quotient) --- 3280,3288 ---- label3 = gen_label_rtx (); label4 = gen_label_rtx (); label5 = gen_label_rtx (); ! do_cmp_and_jump (op1, const0_rtx, LT, compute_mode, label2); emit_jump_insn (gen_blt (label2)); ! do_cmp_and_jump (adjusted_op0, const0_rtx, LT, compute_mode, label1); tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1, quotient, 0, OPTAB_LIB_WIDEN); if (tem != quotient) *************** expand_divmod (rem_flag, code, mode, op0 *** 3298,3306 **** emit_jump_insn (gen_jump (label4)); emit_barrier (); emit_label (label2); ! emit_cmp_insn (adjusted_op0, const0_rtx, GT, NULL_RTX, ! compute_mode, 0, 0); ! emit_jump_insn (gen_bgt (label3)); tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1, quotient, 0, OPTAB_LIB_WIDEN); if (tem != quotient) --- 3294,3300 ---- emit_jump_insn (gen_jump (label4)); emit_barrier (); emit_label (label2); ! do_cmp_and_jump (adjusted_op0, const0_rtx, GT, compute_mode, label3); tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1, quotient, 0, OPTAB_LIB_WIDEN); if (tem != quotient) *************** expand_divmod (rem_flag, code, mode, op0 *** 3340,3348 **** { rtx lab; lab = gen_label_rtx (); ! emit_cmp_insn (t2, const0_rtx, EQ, NULL_RTX, ! compute_mode, 0, 0); ! emit_jump_insn (gen_beq (lab)); expand_inc (t1, const1_rtx); emit_label (lab); quotient = t1; --- 3334,3340 ---- { rtx lab; lab = gen_label_rtx (); ! do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab); expand_inc (t1, const1_rtx); emit_label (lab); quotient = t1; *************** expand_divmod (rem_flag, code, mode, op0 *** 3381,3389 **** /* This could be computed with a branch-less sequence. Save that for later. */ rtx label = gen_label_rtx (); ! emit_cmp_insn (remainder, const0_rtx, EQ, NULL_RTX, ! compute_mode, 0, 0); ! emit_jump_insn (gen_beq (label)); expand_inc (quotient, const1_rtx); expand_dec (remainder, op1); emit_label (label); --- 3373,3380 ---- /* This could be computed with a branch-less sequence. Save that for later. */ rtx label = gen_label_rtx (); ! do_cmp_and_jump (remainder, const0_rtx, EQ, compute_mode, ! label); expand_inc (quotient, const1_rtx); expand_dec (remainder, op1); emit_label (label); *************** expand_divmod (rem_flag, code, mode, op0 *** 3400,3408 **** adjusted_op0 = copy_to_mode_reg (compute_mode, op0); label1 = gen_label_rtx (); label2 = gen_label_rtx (); ! emit_cmp_insn (adjusted_op0, const0_rtx, NE, NULL_RTX, ! compute_mode, 0, 0); ! emit_jump_insn (gen_bne (label1)); emit_move_insn (quotient, const0_rtx); emit_jump_insn (gen_jump (label2)); emit_barrier (); --- 3391,3398 ---- adjusted_op0 = copy_to_mode_reg (compute_mode, op0); label1 = gen_label_rtx (); label2 = gen_label_rtx (); ! do_cmp_and_jump (adjusted_op0, const0_rtx, NE, compute_mode, ! label1); emit_move_insn (quotient, const0_rtx); emit_jump_insn (gen_jump (label2)); emit_barrier (); *************** expand_divmod (rem_flag, code, mode, op0 *** 3442,3450 **** { rtx lab; lab = gen_label_rtx (); ! emit_cmp_insn (t2, const0_rtx, EQ, NULL_RTX, ! compute_mode, 0, 0); ! emit_jump_insn (gen_beq (lab)); expand_inc (t1, const1_rtx); emit_label (lab); quotient = t1; --- 3432,3438 ---- { rtx lab; lab = gen_label_rtx (); ! do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab); expand_inc (t1, const1_rtx); emit_label (lab); quotient = t1; *************** expand_divmod (rem_flag, code, mode, op0 *** 3483,3496 **** Save that for later. */ rtx tem; rtx label = gen_label_rtx (); ! emit_cmp_insn (remainder, const0_rtx, EQ, NULL_RTX, ! compute_mode, 0, 0); ! emit_jump_insn (gen_beq (label)); tem = expand_binop (compute_mode, xor_optab, op0, op1, NULL_RTX, 0, OPTAB_WIDEN); ! emit_cmp_insn (tem, const0_rtx, LT, NULL_RTX, ! compute_mode, 0, 0); ! emit_jump_insn (gen_blt (label)); expand_inc (quotient, const1_rtx); expand_dec (remainder, op1); emit_label (label); --- 3471,3481 ---- Save that for later. */ rtx tem; rtx label = gen_label_rtx (); ! do_cmp_and_jump (remainder, const0_rtx, EQ, compute_mode, ! label); tem = expand_binop (compute_mode, xor_optab, op0, op1, NULL_RTX, 0, OPTAB_WIDEN); ! do_cmp_and_jump (tem, const0_rtx, LT, compute_mode, label); expand_inc (quotient, const1_rtx); expand_dec (remainder, op1); emit_label (label); *************** expand_divmod (rem_flag, code, mode, op0 *** 3511,3522 **** label3 = gen_label_rtx (); label4 = gen_label_rtx (); label5 = gen_label_rtx (); ! emit_cmp_insn (op1, const0_rtx, LT, NULL_RTX, ! compute_mode, 0, 0); ! emit_jump_insn (gen_blt (label2)); ! emit_cmp_insn (adjusted_op0, const0_rtx, GT, NULL_RTX, ! compute_mode, 0, 0); ! emit_jump_insn (gen_bgt (label1)); tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1, quotient, 0, OPTAB_LIB_WIDEN); if (tem != quotient) --- 3496,3504 ---- label3 = gen_label_rtx (); label4 = gen_label_rtx (); label5 = gen_label_rtx (); ! do_cmp_and_jump (op1, const0_rtx, LT, compute_mode, label2); ! do_cmp_and_jump (adjusted_op0, const0_rtx, GT, compute_mode, ! label1); tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1, quotient, 0, OPTAB_LIB_WIDEN); if (tem != quotient) *************** expand_divmod (rem_flag, code, mode, op0 *** 3528,3536 **** emit_jump_insn (gen_jump (label4)); emit_barrier (); emit_label (label2); ! emit_cmp_insn (adjusted_op0, const0_rtx, LT, NULL_RTX, ! compute_mode, 0, 0); ! emit_jump_insn (gen_blt (label3)); tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1, quotient, 0, OPTAB_LIB_WIDEN); if (tem != quotient) --- 3510,3517 ---- emit_jump_insn (gen_jump (label4)); emit_barrier (); emit_label (label2); ! do_cmp_and_jump (adjusted_op0, const0_rtx, LT, compute_mode, ! label3); tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1, quotient, 0, OPTAB_LIB_WIDEN); if (tem != quotient) *************** expand_divmod (rem_flag, code, mode, op0 *** 3596,3603 **** 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); --- 3577,3583 ---- tem = plus_constant (op1, -1); tem = expand_shift (RSHIFT_EXPR, compute_mode, tem, build_int_2 (1, 0), NULL_RTX, 1); ! do_cmp_and_jump (remainder, tem, LEU, compute_mode, label); expand_inc (quotient, const1_rtx); expand_dec (remainder, op1); emit_label (label); *************** expand_divmod (rem_flag, code, mode, op0 *** 3622,3629 **** 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, --- 3602,3608 ---- 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); ! do_cmp_and_jump (tem, abs_op1, LTU, compute_mode, label); tem = expand_binop (compute_mode, xor_optab, op0, op1, NULL_RTX, 0, OPTAB_WIDEN); mask = expand_shift (RSHIFT_EXPR, compute_mode, tem, *************** emit_store_flag_force (target, code, op0 *** 4327,4330 **** --- 4306,4383 ---- emit_label (label); return target; + } + + + /* Perform possibly multi-word comparison and conditional jump as follows: + * if (ARG1 OP ARG2) goto LABEL + * where ARG1 and ARG2 are of mode MODE + * + * The algorithm is based on the code in expr.c:do_jump(). + * + * Note that this does not perform a general comparison. Only variants + * generated within expmed.c are correctly handled, others abort (but could + * be handled if needed). + */ + static void + do_cmp_and_jump (arg1, arg2, op, mode, label) + rtx arg1, arg2, label; + enum rtx_code op; + enum machine_mode mode; + { + /* If this mode is an integer too wide to compare properly, + compare word by word. Rely on cse to optimize constant cases. */ + if (GET_MODE_CLASS (mode) == MODE_INT && !can_compare_p (mode)) + { + rtx label2 = gen_label_rtx (); + + switch (op) + { + case LTU: + do_jump_by_parts_greater_rtx (mode, 1, arg2, arg1, label2, label); + break; + + case LEU: + do_jump_by_parts_greater_rtx (mode, 1, arg1, arg2, label, label2); + break; + + case LT: + do_jump_by_parts_greater_rtx (mode, 0, arg2, arg1, label2, label); + break; + + case GT: + do_jump_by_parts_greater_rtx (mode, 0, arg1, arg2, label2, label); + break; + + case GE: + do_jump_by_parts_greater_rtx (mode, 0, arg2, arg1, label, label2); + break; + + /* do_jump_by_parts_equality_rtx() compares with zero. Luckily + * that's the only equality operations we do */ + case EQ: + if (arg2 != const0_rtx || mode != GET_MODE(arg1)) + abort(); + do_jump_by_parts_equality_rtx (arg1, label2, label); + break; + + case NE: + if (arg2 != const0_rtx || mode != GET_MODE(arg1)) + abort(); + do_jump_by_parts_equality_rtx (arg1, label, label2); + break; + + default: + abort(); + } + + emit_label (label2); + } + else + { + emit_cmp_insn(arg1, arg2, op, NULL_RTX, mode, 0, 0); + if (bcc_gen_fctn[(int) op] == 0) + abort (); + emit_jump_insn ((*bcc_gen_fctn[(int) op]) (label)); + } } *** expr.c~ Sat Mar 28 08:04:29 1998 --- expr.c Fri Apr 10 23:41:40 1998 *************** static void preexpand_calls PROTO((tree) *** 209,215 **** static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx)); void do_jump_by_parts_greater_rtx PROTO((enum machine_mode, int, rtx, rtx, rtx, rtx)); static void do_jump_by_parts_equality PROTO((tree, rtx, rtx)); ! static void do_jump_by_parts_equality_rtx PROTO((rtx, rtx, rtx)); static void do_jump_for_compare PROTO((rtx, rtx, rtx)); static rtx compare PROTO((tree, enum rtx_code, enum rtx_code)); static rtx do_store_flag PROTO((tree, rtx, enum machine_mode, int)); --- 209,215 ---- static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx)); void do_jump_by_parts_greater_rtx PROTO((enum machine_mode, int, rtx, rtx, rtx, rtx)); static void do_jump_by_parts_equality PROTO((tree, rtx, rtx)); ! void do_jump_by_parts_equality_rtx PROTO((rtx, rtx, rtx)); static void do_jump_for_compare PROTO((rtx, rtx, rtx)); static rtx compare PROTO((tree, enum rtx_code, enum rtx_code)); static rtx do_store_flag PROTO((tree, rtx, enum machine_mode, int)); *************** do_jump_by_parts_equality (exp, if_false *** 10747,10753 **** We assume that OP0 has an integer mode that is too wide for the available compare insns. */ ! static void do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label) rtx op0; rtx if_false_label, if_true_label; --- 10747,10753 ---- We assume that OP0 has an integer mode that is too wide for the available compare insns. */ ! void do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label) rtx op0; rtx if_false_label, if_true_label; --- Peter Jeremy (VK2PJ) peter.jeremy@alcatel.com.au Alcatel Australia Limited 41 Mandible St Phone: +61 2 9690 5019 ALEXANDRIA NSW 2015 Fax: +61 2 9690 5247 To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-ports" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199804130152.LAA00492>