loop.c (strength_reduce): Call check_ext_dependant_givs.
authorRichard Henderson <rth@gcc.gnu.org>
Thu, 7 Sep 2000 22:26:37 +0000 (15:26 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Thu, 7 Sep 2000 22:26:37 +0000 (15:26 -0700)
        * loop.c (strength_reduce): Call check_ext_dependant_givs.
        Properly extend the biv initial value for the giv.
        (record_biv): Zero ext_dependant.
        (record_giv): New argument ext_val.  Update all callers.
        (general_induction_var): Likewise.
        (consec_sets_giv): Likewise.
        (simplify_giv_expr): Likewise.  Fill in ext_val if we find
        a sign-extend, zero-extend, or truncate.
        (combine_givs_p): Make sure modes are compatible.
        (check_ext_dependant_givs): New.
        (extend_value_for_giv): New.
        * loop.h (struct induction): Add ext_dependant.
        * unroll.c (iteration_info): Extend the biv initial value for the giv.
        (find_splittable_givs): Likewise.
        (final_giv_value): Likewise.

From-SVN: r36250

gcc/ChangeLog
gcc/loop.c
gcc/loop.h
gcc/unroll.c

index 628f6c78e9fc338aa6c8a9997c3c89278e557772..94d91d799e86e95fd05c19ee9bcc8327c6583b91 100644 (file)
@@ -1,3 +1,21 @@
+2000-09-07  Richard Henderson  <rth@cygnus.com>
+
+       * loop.c (strength_reduce): Call check_ext_dependant_givs.
+       Properly extend the biv initial value for the giv.
+       (record_biv): Zero ext_dependant.
+       (record_giv): New argument ext_val.  Update all callers.
+       (general_induction_var): Likewise.
+       (consec_sets_giv): Likewise.
+       (simplify_giv_expr): Likewise.  Fill in ext_val if we find
+       a sign-extend, zero-extend, or truncate.
+       (combine_givs_p): Make sure modes are compatible.
+       (check_ext_dependant_givs): New.
+       (extend_value_for_giv): New.
+       * loop.h (struct induction): Add ext_dependant.
+       * unroll.c (iteration_info): Extend the biv initial value for the giv.
+       (find_splittable_givs): Likewise.
+       (final_giv_value): Likewise.
+
 2000-09-07  Zack Weinberg  <zack@wolery.cumb.org>
 
        * c-pragma.h: Define HANDLE_GENERIC_PRAGMAS if
@@ -64,9 +82,9 @@ Thu 07-Sep-2000 21:29:00 BST  Neil Booth  <NeilB@earthling.net>
 
 2000-09-07  Catherine Moore  <clm@redhat.com>
 
-        * unroll.c (unroll_loop): Check for unconditional jumps
-        to loop continuation.  Delete if n_iterations is 1.
-        (ujump_to_loop_cont): New routine.
+       * unroll.c (unroll_loop): Check for unconditional jumps
+       to loop continuation.  Delete if n_iterations is 1.
+       (ujump_to_loop_cont): New routine.
 
 2000-09-07  Bernd Schmidt  <bernds@redhat.co.uk>
 
@@ -151,7 +169,7 @@ Thu 07-Sep-2000 21:29:00 BST  Neil Booth  <NeilB@earthling.net>
 
 2000-09-06 Herman A.J. ten Brugge <Haj.Ten.Brugge@net.HCC.nl>
 
-        * flow.c (insn_dead_p): Detect dead memory stores with auto increments.
+       * flow.c (insn_dead_p): Detect dead memory stores with auto increments.
 
 2000-09-06  Kazu Hirata  <kazu@hxi.com>
 
@@ -159,7 +177,7 @@ Thu 07-Sep-2000 21:29:00 BST  Neil Booth  <NeilB@earthling.net>
 
 2000-09-06  Graham Stott  <grahams@cygnus.co.uk>
 
-        * config/i386/i386.h (ADDRESS_COST): Fix typo.
+       * config/i386/i386.h (ADDRESS_COST): Fix typo.
 
 2000-09-06  Zack Weinberg  <zack@wolery.cumb.org>
 
index ce3494bd4153488ce4daa33c1698d8442f2f40ed..a7bba71cbe60ace62e55269f6b7e675e24f86b8d 100644 (file)
@@ -270,17 +270,20 @@ static void record_biv PARAMS ((struct induction *, rtx, rtx, rtx, rtx, rtx *,
 static void check_final_value PARAMS ((const struct loop *,
                                       struct induction *));
 static void record_giv PARAMS ((const struct loop *, struct induction *,
-                               rtx, rtx, rtx, rtx, rtx, int, enum g_types,
-                               int, int, rtx *));
+                               rtx, rtx, rtx, rtx, rtx, rtx, int,
+                               enum g_types, int, int, rtx *));
 static void update_giv_derive PARAMS ((const struct loop *, rtx));
+static void check_ext_dependant_givs PARAMS ((struct iv_class *,
+                                             struct loop_info *));
 static int basic_induction_var PARAMS ((const struct loop *, rtx,
                                        enum machine_mode, rtx, rtx,
                                        rtx *, rtx *, rtx **));
-static rtx simplify_giv_expr PARAMS ((const struct loop *, rtx, int *));
+static rtx simplify_giv_expr PARAMS ((const struct loop *, rtx, rtx *, int *));
 static int general_induction_var PARAMS ((const struct loop *loop, rtx, rtx *,
-                                         rtx *, rtx *, int, int *, enum machine_mode));
+                                         rtx *, rtx *, rtx *, int, int *,
+                                         enum machine_mode));
 static int consec_sets_giv PARAMS ((const struct loop *, int, rtx,
-                                   rtx, rtx, rtx *, rtx *, rtx *));
+                                   rtx, rtx, rtx *, rtx *, rtx *, rtx *));
 static int check_dbra_loop PARAMS ((struct loop *, int));
 static rtx express_from_1 PARAMS ((rtx, rtx, rtx));
 static rtx combine_givs_p PARAMS ((struct induction *, struct induction *));
@@ -4412,6 +4415,10 @@ strength_reduce (loop, insn_count, flags)
            }
        }
 
+      /* Check each extension dependant giv in this class to see if its
+        root biv is safe from wrapping in the interior mode.  */
+      check_ext_dependant_givs (bl, loop_info);
+
       /* Combine all giv's for this iv_class.  */
       combine_givs (bl);
 
@@ -4733,8 +4740,9 @@ strength_reduce (loop, insn_count, flags)
 
              /* Add code at loop start to initialize giv's reduced reg.  */
 
-             emit_iv_add_mult (bl->initial_value, v->mult_val,
-                               v->add_val, v->new_reg, loop_start);
+             emit_iv_add_mult (extend_value_for_giv (v, bl->initial_value),
+                               v->mult_val, v->add_val, v->new_reg,
+                               loop_start);
            }
        }
 
@@ -4799,8 +4807,9 @@ strength_reduce (loop, insn_count, flags)
             not replaceable.  The correct final value is the same as the
             value that the giv starts the reversed loop with.  */
          if (bl->reversed && ! v->replaceable)
-           emit_iv_add_mult (bl->initial_value, v->mult_val,
-                             v->add_val, v->dest_reg, end_insert_before);
+           emit_iv_add_mult (extend_value_for_giv (v, bl->initial_value),
+                             v->mult_val, v->add_val, v->dest_reg,
+                             end_insert_before);
          else if (v->final_value)
            {
              rtx insert_before;
@@ -5057,6 +5066,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
       rtx dest_reg;
       rtx add_val;
       rtx mult_val;
+      rtx ext_val;
       int benefit;
       rtx regnote = 0;
       rtx last_consec_insn;
@@ -5067,11 +5077,11 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
 
       if (/* SET_SRC is a giv.  */
          (general_induction_var (loop, SET_SRC (set), &src_reg, &add_val,
-                                 &mult_val, 0, &benefit, VOIDmode)
+                                 &mult_val, &ext_val, 0, &benefit, VOIDmode)
           /* Equivalent expression is a giv.  */
           || ((regnote = find_reg_note (p, REG_EQUAL, NULL_RTX))
               && general_induction_var (loop, XEXP (regnote, 0), &src_reg,
-                                        &add_val, &mult_val, 0,
+                                        &add_val, &mult_val, &ext_val, 0,
                                         &benefit, VOIDmode)))
          /* Don't try to handle any regs made by loop optimization.
             We have nothing on them in regno_first_uid, etc.  */
@@ -5083,7 +5093,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
              /* or all sets must be consecutive and make a giv.  */
              || (benefit = consec_sets_giv (loop, benefit, p,
                                             src_reg, dest_reg,
-                                            &add_val, &mult_val,
+                                            &add_val, &mult_val, &ext_val,
                                             &last_consec_insn))))
        {
          struct induction *v
@@ -5098,7 +5108,7 @@ check_insn_for_givs (loop, p, not_every_iteration, maybe_multiple)
            p = last_consec_insn;
 
          record_giv (loop, v, p, src_reg, dest_reg, mult_val, add_val,
-                     benefit, DEST_REG, not_every_iteration,
+                     ext_val, benefit, DEST_REG, not_every_iteration,
                      maybe_multiple, NULL_PTR);
 
        }
@@ -5202,6 +5212,7 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
        rtx src_reg;
        rtx add_val;
        rtx mult_val;
+       rtx ext_val;
        int benefit;
 
        /* This code used to disable creating GIVs with mult_val == 1 and
@@ -5210,15 +5221,16 @@ find_mem_givs (loop, x, insn, not_every_iteration, maybe_multiple)
           this one would not be seen.   */
 
        if (general_induction_var (loop, XEXP (x, 0), &src_reg, &add_val,
-                                  &mult_val, 1, &benefit, GET_MODE (x)))
+                                  &mult_val, &ext_val, 1, &benefit,
+                                  GET_MODE (x)))
          {
            /* Found one; record it.  */
            struct induction *v
              = (struct induction *) oballoc (sizeof (struct induction));
 
            record_giv (loop, v, insn, src_reg, addr_placeholder, mult_val,
-                       add_val, benefit, DEST_ADDR, not_every_iteration,
-                       maybe_multiple, &XEXP (x, 0));
+                       add_val, ext_val, benefit, DEST_ADDR,
+                       not_every_iteration, maybe_multiple, &XEXP (x, 0));
 
            v->mem_mode = GET_MODE (x);
          }
@@ -5277,6 +5289,7 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location,
   v->dest_reg = dest_reg;
   v->mult_val = mult_val;
   v->add_val = inc_val;
+  v->ext_dependant = NULL_RTX;
   v->location = location;
   v->mode = GET_MODE (dest_reg);
   v->always_computable = ! not_every_iteration;
@@ -5360,14 +5373,14 @@ record_biv (v, insn, dest_reg, inc_val, mult_val, location,
    LOCATION points to the place where this giv's value appears in INSN.  */
 
 static void
-record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
-           type, not_every_iteration, maybe_multiple, location)
+record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, ext_val,
+           benefit, type, not_every_iteration, maybe_multiple, location)
      const struct loop *loop;
      struct induction *v;
      rtx insn;
      rtx src_reg;
      rtx dest_reg;
-     rtx mult_val, add_val;
+     rtx mult_val, add_val, ext_val;
      int benefit;
      enum g_types type;
      int not_every_iteration, maybe_multiple;
@@ -5389,6 +5402,7 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
   v->dest_reg = dest_reg;
   v->mult_val = mult_val;
   v->add_val = add_val;
+  v->ext_dependant = ext_val;
   v->benefit = benefit;
   v->location = location;
   v->cant_derive = 0;
@@ -5577,6 +5591,24 @@ record_giv (loop, v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
       if (v->no_const_addval)
        fprintf (loop_dump_stream, " ncav");
 
+      if (v->ext_dependant)
+       {
+         switch (GET_CODE (v->ext_dependant))
+           {
+           case SIGN_EXTEND:
+             fprintf (loop_dump_stream, " ext se");
+             break;
+           case ZERO_EXTEND:
+             fprintf (loop_dump_stream, " ext ze");
+             break;
+           case TRUNCATE:
+             fprintf (loop_dump_stream, " ext tr");
+             break;
+           default:
+             abort ();
+           }
+       }
+
       if (GET_CODE (mult_val) == CONST_INT)
        {
          fprintf (loop_dump_stream, " mult ");
@@ -5825,20 +5857,21 @@ update_giv_derive (loop, p)
                 be able to compute a compensation.  */
              else if (biv->insn == p)
                {
-                 tem = 0;
+                 rtx ext_val_dummy;
 
+                 tem = 0;
                  if (biv->mult_val == const1_rtx)
                    tem = simplify_giv_expr (loop,
                                             gen_rtx_MULT (giv->mode,
                                                           biv->add_val,
                                                           giv->mult_val),
-                                            &dummy);
+                                            &ext_val_dummy, &dummy);
 
                  if (tem && giv->derive_adjustment)
                    tem = simplify_giv_expr
                      (loop,
                       gen_rtx_PLUS (giv->mode, tem, giv->derive_adjustment),
-                      &dummy);
+                      &ext_val_dummy, &dummy);
 
                  if (tem)
                    giv->derive_adjustment = tem;
@@ -6058,13 +6091,14 @@ basic_induction_var (loop, x, mode, dest_reg, p, inc_val, mult_val, location)
      such that the value of X is biv * mult + add;  */
 
 static int
-general_induction_var (loop, x, src_reg, add_val, mult_val, is_addr,
-                      pbenefit, addr_mode)
+general_induction_var (loop, x, src_reg, add_val, mult_val, ext_val,
+                      is_addr, pbenefit, addr_mode)
      const struct loop *loop;
      rtx x;
      rtx *src_reg;
      rtx *add_val;
      rtx *mult_val;
+     rtx *ext_val;
      int is_addr;
      int *pbenefit;
      enum machine_mode addr_mode;
@@ -6080,7 +6114,8 @@ general_induction_var (loop, x, src_reg, add_val, mult_val, is_addr,
      Mark our place on the obstack in case we don't find a giv.  */
   storage = (char *) oballoc (0);
   *pbenefit = 0;
-  x = simplify_giv_expr (loop, x, pbenefit);
+  *ext_val = NULL_RTX;
+  x = simplify_giv_expr (loop, x, ext_val, pbenefit);
   if (x == 0)
     {
       obfree (storage);
@@ -6177,9 +6212,10 @@ static int cmp_combine_givs_stats PARAMS ((const PTR, const PTR));
 static int cmp_recombine_givs_stats PARAMS ((const PTR, const PTR));
 
 static rtx
-simplify_giv_expr (loop, x, benefit)
+simplify_giv_expr (loop, x, ext_val, benefit)
      const struct loop *loop;
      rtx x;
+     rtx *ext_val;
      int *benefit;
 {
   enum machine_mode mode = GET_MODE (x);
@@ -6196,8 +6232,8 @@ simplify_giv_expr (loop, x, benefit)
   switch (GET_CODE (x))
     {
     case PLUS:
-      arg0 = simplify_giv_expr (loop, XEXP (x, 0), benefit);
-      arg1 = simplify_giv_expr (loop, XEXP (x, 1), benefit);
+      arg0 = simplify_giv_expr (loop, XEXP (x, 0), ext_val, benefit);
+      arg1 = simplify_giv_expr (loop, XEXP (x, 1), ext_val, benefit);
       if (arg0 == 0 || arg1 == 0)
        return NULL_RTX;
 
@@ -6249,7 +6285,7 @@ simplify_giv_expr (loop, x, benefit)
                                               gen_rtx_PLUS (mode,
                                                             XEXP (arg0, 1),
                                                             arg1)),
-                                benefit);
+                                ext_val, benefit);
 
          default:
            abort ();
@@ -6275,7 +6311,7 @@ simplify_giv_expr (loop, x, benefit)
                                             gen_rtx_PLUS (mode, arg0,
                                                           XEXP (arg1, 0)),
                                             XEXP (arg1, 1)),
-                              benefit);
+                              ext_val, benefit);
 
       /* Now must have MULT + MULT.  Distribute if same biv, else not giv.  */
       if (GET_CODE (arg0) != MULT || GET_CODE (arg1) != MULT)
@@ -6290,7 +6326,7 @@ simplify_giv_expr (loop, x, benefit)
                                              gen_rtx_PLUS (mode,
                                                            XEXP (arg0, 1),
                                                            XEXP (arg1, 1))),
-                               benefit);
+                               ext_val, benefit);
 
     case MINUS:
       /* Handle "a - b" as "a + b * (-1)".  */
@@ -6300,11 +6336,11 @@ simplify_giv_expr (loop, x, benefit)
                                              gen_rtx_MULT (mode,
                                                            XEXP (x, 1),
                                                            constm1_rtx)),
-                               benefit);
+                               ext_val, benefit);
 
     case MULT:
-      arg0 = simplify_giv_expr (loop, XEXP (x, 0), benefit);
-      arg1 = simplify_giv_expr (loop, XEXP (x, 1), benefit);
+      arg0 = simplify_giv_expr (loop, XEXP (x, 0), ext_val, benefit);
+      arg1 = simplify_giv_expr (loop, XEXP (x, 1), ext_val, benefit);
       if (arg0 == 0 || arg1 == 0)
        return NULL_RTX;
 
@@ -6350,7 +6386,7 @@ simplify_giv_expr (loop, x, benefit)
                                                                    XEXP (arg0,
                                                                          1),
                                                                    arg1)),
-                                       benefit);
+                                       ext_val, benefit);
            }
          /* Porpagate the MULT expressions to the intermost nodes.  */
          else if (GET_CODE (arg0) == PLUS)
@@ -6366,7 +6402,7 @@ simplify_giv_expr (loop, x, benefit)
                                                                    XEXP (arg0,
                                                                          1),
                                                                    arg1)),
-                                       benefit);
+                                       ext_val, benefit);
            }
          return gen_rtx_USE (mode, gen_rtx_MULT (mode, arg0, arg1));
 
@@ -6378,7 +6414,7 @@ simplify_giv_expr (loop, x, benefit)
                                                  gen_rtx_MULT (mode,
                                                                XEXP (arg0, 1),
                                                                arg1)),
-                                   benefit);
+                                   ext_val, benefit);
 
        case PLUS:
          /* (a + invar_1) * invar_2.  Distribute.  */
@@ -6390,7 +6426,7 @@ simplify_giv_expr (loop, x, benefit)
                                                  gen_rtx_MULT (mode,
                                                                XEXP (arg0, 1),
                                                                arg1)),
-                                   benefit);
+                                   ext_val, benefit);
 
        default:
          abort ();
@@ -6407,13 +6443,13 @@ simplify_giv_expr (loop, x, benefit)
                                         XEXP (x, 0),
                                         GEN_INT ((HOST_WIDE_INT) 1
                                                  << INTVAL (XEXP (x, 1)))),
-                          benefit);
+                          ext_val, benefit);
 
     case NEG:
       /* "-a" is "a * (-1)" */
       return simplify_giv_expr (loop,
                                gen_rtx_MULT (mode, XEXP (x, 0), constm1_rtx),
-                               benefit);
+                               ext_val, benefit);
 
     case NOT:
       /* "~a" is "-a - 1". Silly, but easy.  */
@@ -6421,13 +6457,30 @@ simplify_giv_expr (loop, x, benefit)
                                gen_rtx_MINUS (mode,
                                               gen_rtx_NEG (mode, XEXP (x, 0)),
                                               const1_rtx),
-                               benefit);
+                               ext_val, benefit);
 
     case USE:
       /* Already in proper form for invariant.  */
       return x;
 
-    case REG:
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
+    case TRUNCATE:
+      /* Conditionally recognize extensions of simple IVs.  After we've
+        computed loop traversal counts and verified the range of the 
+        source IV, we'll reevaluate this as a GIV.  */
+      if (*ext_val == NULL_RTX)
+       {
+         arg0 = simplify_giv_expr (loop, XEXP (x, 0), ext_val, benefit);
+         if (arg0 && *ext_val == NULL_RTX && GET_CODE (arg0) == REG)
+           {
+             *ext_val = gen_rtx_fmt_e (GET_CODE (x), mode, arg0);
+             return arg0;
+           }
+       }
+      goto do_default;
+
+  case REG:
       /* If this is a new register, we can't deal with it.  */
       if (REGNO (x) >= max_reg_before_loop)
        return 0;
@@ -6466,10 +6519,22 @@ simplify_giv_expr (loop, x, benefit)
 
            if (v->derive_adjustment)
              tem = gen_rtx_MINUS (mode, tem, v->derive_adjustment);
-           return simplify_giv_expr (loop, tem, benefit);
+           arg0 = simplify_giv_expr (loop, tem, ext_val, benefit);
+           if (*ext_val)
+             {
+               if (!v->ext_dependant)
+                 return arg0;
+             }
+           else
+             {
+               *ext_val = v->ext_dependant;
+               return arg0;
+             }
+           return 0;
          }
 
        default:
+       do_default:
          /* If it isn't an induction variable, and it is invariant, we
             may be able to simplify things further by looking through
             the bits we just moved outside the loop.  */
@@ -6486,7 +6551,7 @@ simplify_giv_expr (loop, x, benefit)
                       this one is going away.  */
                    if (m->match)
                      return simplify_giv_expr (loop, m->match->set_dest,
-                                               benefit);
+                                               ext_val, benefit);
 
                    /* If consec is non-zero, this is a member of a group of
                       instructions that were moved together.  We handle this
@@ -6520,7 +6585,8 @@ simplify_giv_expr (loop, x, benefit)
                            || GET_CODE (tem) == CONST_INT
                            || GET_CODE (tem) == SYMBOL_REF)
                          {
-                           tem = simplify_giv_expr (loop, tem, benefit);
+                           tem = simplify_giv_expr (loop, tem, ext_val,
+                                                    benefit);
                            if (tem)
                              return tem;
                          }
@@ -6530,7 +6596,7 @@ simplify_giv_expr (loop, x, benefit)
                            && GET_CODE (XEXP (XEXP (tem, 0), 1)) == CONST_INT)
                          {
                            tem = simplify_giv_expr (loop, XEXP (tem, 0),
-                                                    benefit);
+                                                    ext_val, benefit);
                            if (tem)
                              return tem;
                          }
@@ -6635,7 +6701,7 @@ sge_plus (mode, x, y)
 
 static int
 consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
-                add_val, mult_val, last_consec_insn)
+                add_val, mult_val, ext_val, last_consec_insn)
      const struct loop *loop;
      int first_benefit;
      rtx p;
@@ -6643,6 +6709,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
      rtx dest_reg;
      rtx *add_val;
      rtx *mult_val;
+     rtx *ext_val;
      rtx *last_consec_insn;
 {
   int count;
@@ -6666,6 +6733,7 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
   v->benefit = first_benefit;
   v->cant_derive = 0;
   v->derive_adjustment = 0;
+  v->ext_dependant = NULL_RTX;
 
   REG_IV_TYPE (REGNO (dest_reg)) = GENERAL_INDUCT;
   REG_IV_INFO (REGNO (dest_reg)) = v;
@@ -6686,12 +6754,13 @@ consec_sets_giv (loop, first_benefit, p, src_reg, dest_reg,
          && GET_CODE (SET_DEST (set)) == REG
          && SET_DEST (set) == dest_reg
          && (general_induction_var (loop, SET_SRC (set), &src_reg,
-                                    add_val, mult_val, 0, &benefit, VOIDmode)
+                                    add_val, mult_val, ext_val, 0,
+                                    &benefit, VOIDmode)
              /* Giv created by equivalent expression.  */
              || ((temp = find_reg_note (p, REG_EQUAL, NULL_RTX))
                  && general_induction_var (loop, XEXP (temp, 0), &src_reg,
-                                           add_val, mult_val, 0, &benefit,
-                                           VOIDmode)))
+                                           add_val, mult_val, ext_val, 0,
+                                           &benefit, VOIDmode)))
          && src_reg == v->src_reg)
        {
          if (find_reg_note (p, REG_RETVAL, NULL_RTX))
@@ -6921,25 +6990,36 @@ static rtx
 combine_givs_p (g1, g2)
      struct induction *g1, *g2;
 {
-  rtx tem = express_from (g1, g2);
+  rtx comb, ret;
+
+  /* With the introduction of ext dependant givs, we must care for modes.
+     G2 must not use a wider mode than G1.  */
+  if (GET_MODE_SIZE (g1->mode) < GET_MODE_SIZE (g2->mode))
+    return NULL_RTX;
+
+  ret = comb = express_from (g1, g2);
+  if (comb == NULL_RTX)
+    return NULL_RTX;
+  if (g1->mode != g2->mode)
+    ret = gen_lowpart (g2->mode, comb);
 
   /* If these givs are identical, they can be combined.  We use the results
      of express_from because the addends are not in a canonical form, so
      rtx_equal_p is a weaker test.  */
   /* But don't combine a DEST_REG giv with a DEST_ADDR giv; we want the
      combination to be the other way round.  */
-  if (tem == g1->dest_reg
+  if (comb == g1->dest_reg
       && (g1->giv_type == DEST_REG || g2->giv_type == DEST_ADDR))
     {
-      return g1->dest_reg;
+      return ret;
     }
 
   /* If G2 can be expressed as a function of G1 and that function is valid
      as an address and no more expensive than using a register for G2,
      the expression of G2 in terms of G1 can be used.  */
-  if (tem != NULL_RTX
+  if (ret != NULL_RTX
       && g2->giv_type == DEST_ADDR
-      && memory_address_p (g2->mem_mode, tem)
+      && memory_address_p (g2->mem_mode, ret)
       /* ??? Looses, especially with -fforce-addr, where *g2->location
         will always be a register, and so anything more complicated
         gets discarded.  */
@@ -6952,12 +7032,197 @@ combine_givs_p (g1, g2)
 #endif
       )
     {
-      return tem;
+      return ret;
     }
 
   return NULL_RTX;
 }
 \f
+/* Check each extension dependant giv in this class to see if its
+   root biv is safe from wrapping in the interior mode, which would
+   make the giv illegal.  */
+
+static void
+check_ext_dependant_givs (bl, loop_info)
+     struct iv_class *bl;
+     struct loop_info *loop_info;
+{
+  int ze_ok = 0, se_ok = 0, info_ok = 0;
+  enum machine_mode biv_mode = GET_MODE (bl->biv->src_reg);
+  HOST_WIDE_INT start_val;
+  unsigned HOST_WIDE_INT u_end_val, u_start_val;
+  rtx incr = pc_rtx;
+  struct induction *v;
+
+  /* Make sure the iteration data is available.  We must have
+     constants in order to be certain of no overflow.  */
+  /* ??? An unknown iteration count with an increment of +-1
+     combined with friendly exit tests of against an invariant
+     value is also ameanable to optimization.  Not implemented.  */
+  if (loop_info->n_iterations > 0
+      && bl->initial_value
+      && GET_CODE (bl->initial_value) == CONST_INT
+      && (incr = biv_total_increment (bl))
+      && GET_CODE (incr) == CONST_INT
+      /* Make sure the host can represent the arithmetic.  */
+      && HOST_BITS_PER_WIDE_INT >= GET_MODE_BITSIZE (biv_mode))
+    {
+      unsigned HOST_WIDE_INT abs_incr, total_incr;
+      HOST_WIDE_INT s_end_val;
+      int neg_incr;
+
+      info_ok = 1;
+      start_val = INTVAL (bl->initial_value);
+      u_start_val = start_val;
+          
+      neg_incr = 0, abs_incr = INTVAL (incr);
+      if (INTVAL (incr) < 0)
+       neg_incr = 1, abs_incr = -abs_incr;
+      total_incr = abs_incr * loop_info->n_iterations;
+
+      /* Check for host arithmatic overflow.  */
+      if (total_incr / loop_info->n_iterations == abs_incr)
+       {
+         unsigned HOST_WIDE_INT u_max;
+         HOST_WIDE_INT s_max;
+
+         u_end_val = start_val + (neg_incr ? -total_incr : total_incr);
+         s_end_val = u_end_val;
+         u_max = GET_MODE_MASK (biv_mode);
+         s_max = u_max >> 1;
+                 
+         /* Check zero extension of biv ok.  */
+         if (start_val >= 0
+             /* Check for host arithmatic overflow.  */
+             && (neg_incr
+                 ? u_end_val < u_start_val
+                 : u_end_val > u_start_val)
+             /* Check for target arithmetic overflow.  */
+             && (neg_incr
+                 ? 1 /* taken care of with host overflow */
+                 : u_end_val <= u_max))
+           {
+             ze_ok = 1;
+           }
+                 
+         /* Check sign extension of biv ok.  */
+         /* ??? While it is true that overflow with signed and pointer
+            arithmetic is undefined, I fear too many programmers don't
+            keep this fact in mind -- myself included on occasion.
+            So leave alone with the signed overflow optimizations.  */
+         if (start_val >= -s_max - 1
+             /* Check for host arithmatic overflow.  */
+             && (neg_incr
+                 ? s_end_val < start_val
+                 : s_end_val > start_val)
+             /* Check for target arithmetic overflow.  */
+             && (neg_incr
+                 ? s_end_val >= -s_max - 1
+                 : s_end_val <= s_max))
+           {
+             se_ok = 1;
+           }
+       }
+    }
+
+  /* Invalidate givs that fail the tests.  */
+  for (v = bl->giv; v; v = v->next_iv)
+    if (v->ext_dependant)
+      {
+       enum rtx_code code = GET_CODE (v->ext_dependant);
+       int ok = 0;
+
+       switch (code)
+         {
+         case SIGN_EXTEND:
+           ok = se_ok;
+           break;
+         case ZERO_EXTEND:
+           ok = ze_ok;
+           break;
+
+         case TRUNCATE:
+           /* We don't know whether this value is being used as either
+              signed or unsigned, so to safely truncate we must satisfy
+              both.  The initial check here verifies the BIV itself; 
+              once that is successful we may check its range wrt the
+              derived GIV.  */
+           if (se_ok && ze_ok)
+             {
+               enum machine_mode outer_mode = GET_MODE (v->ext_dependant);
+               unsigned HOST_WIDE_INT max = GET_MODE_MASK (outer_mode) >> 1;
+
+               /* We know from the above that both endpoints are nonnegative,
+                  and that there is no wrapping.  Verify that both endpoints
+                  are within the (signed) range of the outer mode.  */
+               if (u_start_val <= max && u_end_val <= max)
+                 ok = 1;
+             }
+           break;
+
+         default:
+           abort ();
+         }
+
+       if (ok)
+         {
+           if (loop_dump_stream)
+             {
+               fprintf(loop_dump_stream,
+                       "Verified ext dependant giv at %d of reg %d\n",
+                       INSN_UID (v->insn), bl->regno);
+             }
+         }
+       else
+         {
+           if (loop_dump_stream)
+             {
+               const char *why;
+
+               if (info_ok)
+                 why = "biv iteration values overflowed";
+               else
+                 {
+                   if (incr == pc_rtx)
+                     incr = biv_total_increment (bl);
+                   if (incr == const1_rtx)
+                     why = "biv iteration info incomplete; incr by 1";
+                   else
+                     why = "biv iteration info incomplete";
+                 }
+
+               fprintf(loop_dump_stream,
+                       "Failed ext dependant giv at %d, %s\n",
+                       INSN_UID (v->insn), why);
+             }
+           v->ignore = 1;
+         }
+      }
+}
+
+/* Generate a version of VALUE in a mode appropriate for initializing V.  */
+
+rtx
+extend_value_for_giv (v, value)
+     struct induction *v;
+     rtx value;
+{
+  rtx ext_dep = v->ext_dependant;
+
+  if (! ext_dep)
+    return value;
+
+  /* Recall that check_ext_dependant_givs verified that the known bounds
+     of a biv did not overflow or wrap with respect to the extension for
+     the giv.  Therefore, constants need no additional adjustment.  */
+  if (CONSTANT_P (value) && GET_MODE (value) == VOIDmode)
+    return value;
+
+  /* Otherwise, we must adjust the value to compensate for the
+     differing modes of the biv and the giv.  */
+  return gen_rtx_fmt_e (GET_CODE (ext_dep), GET_MODE (ext_dep), value);
+}
+\f
 struct combine_givs_stats
 {
   int giv_number;
index 7d4c7cea41a8e5a2aafe30777357cbe623ef9720..1bc9a35ae634e5cf0162effe1bde8e8d50784b91 100644 (file)
@@ -115,6 +115,8 @@ struct induction
                                   subtracted from add_val when this giv
                                   derives another.  This occurs when the
                                   giv spans a biv update by incrementation. */
+  rtx ext_dependant;           /* If nonzero, is a sign or zero extension
+                                  if a biv on which this giv is dependant.  */
   struct induction *next_iv;   /* For givs, links together all givs that are
                                   based on the same biv.  For bivs, links
                                   together all biv entries that refer to the
@@ -238,6 +240,7 @@ int loop_invariant_p PARAMS ((const struct loop *, rtx));
 rtx get_condition_for_loop PARAMS ((const struct loop *, rtx));
 void emit_iv_add_mult PARAMS ((rtx, rtx, rtx, rtx, rtx));
 rtx express_from PARAMS ((struct induction *, struct induction *));
+rtx extend_value_for_giv PARAMS ((struct induction *, rtx));
 
 void unroll_loop PARAMS ((struct loop *, int, rtx, int));
 rtx biv_total_increment PARAMS ((struct iv_class *));
@@ -251,7 +254,7 @@ void emit_unrolled_add PARAMS ((rtx, rtx, rtx));
 int back_branch_in_range_p PARAMS ((const struct loop *, rtx));
 
 int loop_insn_first_p PARAMS ((rtx, rtx));
-typedef rtx (*loop_insn_callback ) PARAMS ((struct loop *, rtx, int, int));
+typedef rtx (*loop_insn_callback) PARAMS ((struct loop *, rtx, int, int));
 void for_each_insn_in_loop PARAMS ((struct loop *, loop_insn_callback));
 
 /* Forward declarations for non-static functions declared in doloop.c.  */
index 36e6c57b9f81b4a127b98f15dab23debf5c99c3a..51a469dcb4808bed8b3a854a694c971f31e8f95a 100644 (file)
@@ -2495,6 +2495,7 @@ iteration_info (loop, iteration_var, initial_value, increment)
     {
       HOST_WIDE_INT offset = 0;
       struct induction *v = REG_IV_INFO (REGNO (iteration_var));
+      rtx biv_initial_value;
 
       if (REGNO (v->src_reg) >= max_reg_before_loop)
        abort ();
@@ -2527,11 +2528,13 @@ iteration_info (loop, iteration_var, initial_value, increment)
        fprintf (loop_dump_stream,
                 "Loop unrolling: Giv iterator, initial value bias %ld.\n",
                 (long) offset);
+
       /* Initial value is mult_val times the biv's initial value plus
         add_val.  Only useful if it is a constant.  */
+      biv_initial_value = extend_value_for_giv (v, bl->initial_value);
       *initial_value
        = fold_rtx_mult_add (v->mult_val,
-                            plus_constant (bl->initial_value, offset),
+                            plus_constant (biv_initial_value, offset),
                             v->add_val, v->mode);
     }
   else
@@ -2895,6 +2898,7 @@ find_splittable_givs (loop, bl, unroll_type, increment, unroll_number)
                                loop->start);
              biv_initial_value = tem;
            }
+         biv_initial_value = extend_value_for_giv (v, biv_initial_value);
          value = fold_rtx_mult_add (v->mult_val, biv_initial_value,
                                     v->add_val, v->mode);
        }
@@ -3456,10 +3460,11 @@ final_giv_value (loop, v)
          insert_before = NEXT_INSN (loop_end);
 
          /* Put the final biv value in tem.  */
-         tem = gen_reg_rtx (bl->biv->mode);
+         tem = gen_reg_rtx (v->mode);
          record_base_value (REGNO (tem), bl->biv->add_val, 0);
          emit_iv_add_mult (increment, GEN_INT (n_iterations),
-                           bl->initial_value, tem, insert_before);
+                           extend_value_for_giv (v, bl->initial_value),
+                           tem, insert_before);
 
          /* Subtract off extra increments as we find them.  */
          for (insn = NEXT_INSN (v->insn); insn != loop_end;