diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4890db352f2e..07443b6363b5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2002-05-30 Eric Botcazou + + * expmed.c (const_mult_add_overflow_p): New. + * expr.h: Declare it. + * loop.c (maybe_eliminate_biv_1) [COMPARE]: Use it. + Don't eliminate the biv if the giv has a constant multiplier and + the rhs argument of the comparison does satisfy the predicate. + Use expand_mult_add to compute the replacement constant. + 2002-05-30 Osku Salerma * c-common.c (c_common_attribute_table): Add "may_alias" entry. diff --git a/gcc/expmed.c b/gcc/expmed.c index 5a4c24ea68ac..9419681dcae1 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -4156,6 +4156,44 @@ make_tree (type, x) } } +/* Check whether the multiplication X * MULT + ADD overflows. + X, MULT and ADD must be CONST_*. + MODE is the machine mode for the computation. + X and MULT must have mode MODE. ADD may have a different mode. + So can X (defaults to same as MODE). + UNSIGNEDP is non-zero to do unsigned multiplication. */ + +bool +const_mult_add_overflow_p (x, mult, add, mode, unsignedp) + rtx x, mult, add; + enum machine_mode mode; + int unsignedp; +{ + tree type, mult_type, add_type, result; + + type = (*lang_hooks.types.type_for_mode) (mode, unsignedp); + + /* In order to get a proper overflow indication from an unsigned + type, we have to pretend that it's a sizetype. */ + mult_type = type; + if (unsignedp) + { + mult_type = copy_node (type); + TYPE_IS_SIZETYPE (mult_type) = 1; + } + + add_type = (GET_MODE (add) == VOIDmode ? mult_type + : (*lang_hooks.types.type_for_mode) (GET_MODE (add), unsignedp)); + + result = fold (build (PLUS_EXPR, mult_type, + fold (build (MULT_EXPR, mult_type, + make_tree (mult_type, x), + make_tree (mult_type, mult))), + make_tree (add_type, add))); + + return TREE_CONSTANT_OVERFLOW (result); +} + /* Return an rtx representing the value of X * MULT + ADD. TARGET is a suggestion for where to store the result (an rtx). MODE is the machine mode for the computation. diff --git a/gcc/expr.h b/gcc/expr.h index 91ffa3f0507d..fa51a8a3191e 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -758,6 +758,7 @@ extern rtx extract_bit_field PARAMS ((rtx, unsigned HOST_WIDE_INT, enum machine_mode, enum machine_mode, HOST_WIDE_INT)); extern rtx expand_mult PARAMS ((enum machine_mode, rtx, rtx, rtx, int)); +extern bool const_mult_add_overflow_p PARAMS ((rtx, rtx, rtx, enum machine_mode, int)); extern rtx expand_mult_add PARAMS ((rtx, rtx, rtx, rtx,enum machine_mode, int)); extern rtx expand_mult_highpart_adjust PARAMS ((enum machine_mode, rtx, rtx, rtx, rtx, int)); diff --git a/gcc/loop.c b/gcc/loop.c index 8581af2746ec..20c5f1dab0ab 100644 --- a/gcc/loop.c +++ b/gcc/loop.c @@ -8863,6 +8863,22 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn) if (! biv_elimination_giv_has_0_offset (bl->biv, v, insn)) continue; + /* Don't eliminate if the linear combination that makes up + the giv overflows when it is applied to ARG. */ + if (GET_CODE (arg) == CONST_INT) + { + rtx add_val; + + if (GET_CODE (v->add_val) == CONST_INT) + add_val = v->add_val; + else + add_val = const0_rtx; + + if (const_mult_add_overflow_p (arg, v->mult_val, + add_val, mode, 1)) + continue; + } + if (! eliminate_p) return 1; @@ -8873,13 +8889,10 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn) the derived constant can be directly placed in the COMPARE, do so. */ if (GET_CODE (arg) == CONST_INT - && GET_CODE (v->mult_val) == CONST_INT && GET_CODE (v->add_val) == CONST_INT) { - validate_change (insn, &XEXP (x, arg_operand), - GEN_INT (INTVAL (arg) - * INTVAL (v->mult_val) - + INTVAL (v->add_val)), 1); + tem = expand_mult_add (arg, NULL_RTX, v->mult_val, + v->add_val, mode, 1); } else { @@ -8888,8 +8901,10 @@ maybe_eliminate_biv_1 (loop, x, insn, bl, eliminate_p, where_bb, where_insn) loop_iv_add_mult_emit_before (loop, arg, v->mult_val, v->add_val, tem, where_bb, where_insn); - validate_change (insn, &XEXP (x, arg_operand), tem, 1); } + + validate_change (insn, &XEXP (x, arg_operand), tem, 1); + if (apply_change_group ()) return 1; }