expmed.c (const_mult_add_overflow_p): New.
authorEric Botcazou <ebotcazou@multimania.com>
Thu, 30 May 2002 21:33:32 +0000 (21:33 +0000)
committerRichard Henderson <rth@gcc.gnu.org>
Thu, 30 May 2002 21:33:32 +0000 (14:33 -0700)
        * 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.

From-SVN: r54075

gcc/ChangeLog
gcc/expmed.c
gcc/expr.h
gcc/loop.c

index 4890db352f2eb3efde36ecc714258c0e9284176e..07443b6363b56d6777b44f609b4fecbef5bbd8f7 100644 (file)
@@ -1,3 +1,12 @@
+2002-05-30  Eric Botcazou  <ebotcazou@multimania.com>
+
+       * 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  <osku@iki.fi>
 
        * c-common.c (c_common_attribute_table): Add "may_alias" entry.
index 5a4c24ea68ac9685cab7e4a2d173af12666705d8..9419681dcae1c735fd7f82a5553ee01fd7da4b33 100644 (file)
@@ -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.
index 91ffa3f0507dde0d1f932cb0adcf1c398a6093e4..fa51a8a3191ec9021faed0d46cbabcf6bad75eaa 100644 (file)
@@ -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));
 
index 8581af2746ec564d5372cf1ebe6b171288116399..20c5f1dab0ab4cf47df1c06db25a91566a457a77 100644 (file)
@@ -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;
              }