OSDN Git Service

* config/alpha/alpha.c (alpha_sa_size): Force procedure type to
[pf3gnuchains/gcc-fork.git] / gcc / tree-chrec.c
index d16522f..33d9f18 100644 (file)
@@ -1,12 +1,13 @@
 /* Chains of recurrences.
 /* Chains of recurrences.
-   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
-   Contributed by Sebastian Pop <s.pop@laposte.net>
+   Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
+   Contributed by Sebastian Pop <pop@cri.ensmp.fr>
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* This file implements operations on chains of recurrences.  Chains
    of recurrences are used for modeling evolution functions of scalar
 
 /* This file implements operations on chains of recurrences.  Chains
    of recurrences are used for modeling evolution functions of scalar
@@ -28,13 +28,17 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "errors.h"
 #include "ggc.h"
 #include "tree.h"
 #include "ggc.h"
 #include "tree.h"
+#include "real.h"
 #include "diagnostic.h"
 #include "diagnostic.h"
-#include "varray.h"
+#include "cfgloop.h"
+#include "tree-flow.h"
 #include "tree-chrec.h"
 #include "tree-pass.h"
 #include "tree-chrec.h"
 #include "tree-pass.h"
+#include "params.h"
+#include "flags.h"
+#include "tree-scalar-evolution.h"
 
 \f
 
 
 \f
 
@@ -43,7 +47,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 /* Determines whether CST is not a constant evolution.  */
 
 static inline bool
 /* Determines whether CST is not a constant evolution.  */
 
 static inline bool
-is_not_constant_evolution (tree cst)
+is_not_constant_evolution (const_tree cst)
 {
   return (TREE_CODE (cst) == POLYNOMIAL_CHREC);
 }
 {
   return (TREE_CODE (cst) == POLYNOMIAL_CHREC);
 }
@@ -56,14 +60,12 @@ chrec_fold_poly_cst (enum tree_code code,
                     tree poly, 
                     tree cst)
 {
                     tree poly, 
                     tree cst)
 {
-#if defined ENABLE_CHECKING
-  if (poly == NULL_TREE
-      || cst == NULL_TREE
-      || TREE_CODE (poly) != POLYNOMIAL_CHREC
-      || is_not_constant_evolution (cst))
-    abort ();
-#endif
-  
+  gcc_assert (poly);
+  gcc_assert (cst);
+  gcc_assert (TREE_CODE (poly) == POLYNOMIAL_CHREC);
+  gcc_assert (!is_not_constant_evolution (cst));
+  gcc_assert (type == chrec_type (poly));
+
   switch (code)
     {
     case PLUS_EXPR:
   switch (code)
     {
     case PLUS_EXPR:
@@ -98,22 +100,27 @@ chrec_fold_plus_poly_poly (enum tree_code code,
                           tree poly1)
 {
   tree left, right;
                           tree poly1)
 {
   tree left, right;
-  
-#if defined ENABLE_CHECKING
-  if (poly0 == NULL_TREE
-      || poly1 == NULL_TREE
-      || TREE_CODE (poly0) != POLYNOMIAL_CHREC
-      || TREE_CODE (poly1) != POLYNOMIAL_CHREC)
-    abort ();
-#endif
+  struct loop *loop0 = get_chrec_loop (poly0);
+  struct loop *loop1 = get_chrec_loop (poly1);
+  tree rtype = code == POINTER_PLUS_EXPR ? sizetype : type;
+
+  gcc_assert (poly0);
+  gcc_assert (poly1);
+  gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC);
+  gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC);
+  if (POINTER_TYPE_P (chrec_type (poly0)))
+    gcc_assert (chrec_type (poly1) == sizetype);
+  else
+    gcc_assert (chrec_type (poly0) == chrec_type (poly1));
+  gcc_assert (type == chrec_type (poly0));
   
   /*
     {a, +, b}_1 + {c, +, d}_2  ->  {{a, +, b}_1 + c, +, d}_2,
     {a, +, b}_2 + {c, +, d}_1  ->  {{c, +, d}_1 + a, +, b}_2,
     {a, +, b}_x + {c, +, d}_x  ->  {a+c, +, b+d}_x.  */
   
   /*
     {a, +, b}_1 + {c, +, d}_2  ->  {{a, +, b}_1 + c, +, d}_2,
     {a, +, b}_2 + {c, +, d}_1  ->  {{c, +, d}_1 + a, +, b}_2,
     {a, +, b}_x + {c, +, d}_x  ->  {a+c, +, b+d}_x.  */
-  if (CHREC_VARIABLE (poly0) < CHREC_VARIABLE (poly1))
+  if (flow_loop_nested_p (loop0, loop1))
     {
     {
-      if (code == PLUS_EXPR)
+      if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR)
        return build_polynomial_chrec 
          (CHREC_VARIABLE (poly1), 
           chrec_fold_plus (type, poly0, CHREC_LEFT (poly1)),
        return build_polynomial_chrec 
          (CHREC_VARIABLE (poly1), 
           chrec_fold_plus (type, poly0, CHREC_LEFT (poly1)),
@@ -123,12 +130,14 @@ chrec_fold_plus_poly_poly (enum tree_code code,
          (CHREC_VARIABLE (poly1), 
           chrec_fold_minus (type, poly0, CHREC_LEFT (poly1)),
           chrec_fold_multiply (type, CHREC_RIGHT (poly1), 
          (CHREC_VARIABLE (poly1), 
           chrec_fold_minus (type, poly0, CHREC_LEFT (poly1)),
           chrec_fold_multiply (type, CHREC_RIGHT (poly1), 
-                               convert (type, integer_minus_one_node)));
+                               SCALAR_FLOAT_TYPE_P (type)
+                               ? build_real (type, dconstm1)
+                               : build_int_cst_type (type, -1)));
     }
   
     }
   
-  if (CHREC_VARIABLE (poly0) > CHREC_VARIABLE (poly1))
+  if (flow_loop_nested_p (loop1, loop0))
     {
     {
-      if (code == PLUS_EXPR)
+      if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR)
        return build_polynomial_chrec 
          (CHREC_VARIABLE (poly0), 
           chrec_fold_plus (type, CHREC_LEFT (poly0), poly1),
        return build_polynomial_chrec 
          (CHREC_VARIABLE (poly0), 
           chrec_fold_plus (type, CHREC_LEFT (poly0), poly1),
@@ -139,13 +148,17 @@ chrec_fold_plus_poly_poly (enum tree_code code,
           chrec_fold_minus (type, CHREC_LEFT (poly0), poly1),
           CHREC_RIGHT (poly0));
     }
           chrec_fold_minus (type, CHREC_LEFT (poly0), poly1),
           CHREC_RIGHT (poly0));
     }
-  
-  if (code == PLUS_EXPR)
+  /* This function should never be called for chrecs of loops that
+     do not belong to the same loop nest.  */
+  gcc_assert (loop0 == loop1);
+
+  if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR)
     {
       left = chrec_fold_plus 
        (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1));
       right = chrec_fold_plus 
     {
       left = chrec_fold_plus 
        (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1));
       right = chrec_fold_plus 
-       (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1));
+       (rtype, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1));
     }
   else
     {
     }
   else
     {
@@ -171,55 +184,60 @@ chrec_fold_multiply_poly_poly (tree type,
                               tree poly0, 
                               tree poly1)
 {
                               tree poly0, 
                               tree poly1)
 {
-#if defined ENABLE_CHECKING
-  if (poly0 == NULL_TREE
-      || poly1 == NULL_TREE
-      || TREE_CODE (poly0) != POLYNOMIAL_CHREC
-      || TREE_CODE (poly1) != POLYNOMIAL_CHREC)
-    abort ();
-#endif
+  tree t0, t1, t2;
+  int var;
+  struct loop *loop0 = get_chrec_loop (poly0);
+  struct loop *loop1 = get_chrec_loop (poly1);
+
+  gcc_assert (poly0);
+  gcc_assert (poly1);
+  gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC);
+  gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC);
+  gcc_assert (chrec_type (poly0) == chrec_type (poly1));
+  gcc_assert (type == chrec_type (poly0));
   
   /* {a, +, b}_1 * {c, +, d}_2  ->  {c*{a, +, b}_1, +, d}_2,
      {a, +, b}_2 * {c, +, d}_1  ->  {a*{c, +, d}_1, +, b}_2,
      {a, +, b}_x * {c, +, d}_x  ->  {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x.  */
   
   /* {a, +, b}_1 * {c, +, d}_2  ->  {c*{a, +, b}_1, +, d}_2,
      {a, +, b}_2 * {c, +, d}_1  ->  {a*{c, +, d}_1, +, b}_2,
      {a, +, b}_x * {c, +, d}_x  ->  {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x.  */
-  if (CHREC_VARIABLE (poly0) < CHREC_VARIABLE (poly1))
+  if (flow_loop_nested_p (loop0, loop1))
     /* poly0 is a constant wrt. poly1.  */
     return build_polynomial_chrec 
       (CHREC_VARIABLE (poly1), 
        chrec_fold_multiply (type, CHREC_LEFT (poly1), poly0),
        CHREC_RIGHT (poly1));
   
     /* poly0 is a constant wrt. poly1.  */
     return build_polynomial_chrec 
       (CHREC_VARIABLE (poly1), 
        chrec_fold_multiply (type, CHREC_LEFT (poly1), poly0),
        CHREC_RIGHT (poly1));
   
-  if (CHREC_VARIABLE (poly1) < CHREC_VARIABLE (poly0))
+  if (flow_loop_nested_p (loop1, loop0))
     /* poly1 is a constant wrt. poly0.  */
     return build_polynomial_chrec 
       (CHREC_VARIABLE (poly0), 
        chrec_fold_multiply (type, CHREC_LEFT (poly0), poly1),
        CHREC_RIGHT (poly0));
     /* poly1 is a constant wrt. poly0.  */
     return build_polynomial_chrec 
       (CHREC_VARIABLE (poly0), 
        chrec_fold_multiply (type, CHREC_LEFT (poly0), poly1),
        CHREC_RIGHT (poly0));
-  
+  gcc_assert (loop0 == loop1);
+
   /* poly0 and poly1 are two polynomials in the same variable,
      {a, +, b}_x * {c, +, d}_x  ->  {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x.  */
   /* poly0 and poly1 are two polynomials in the same variable,
      {a, +, b}_x * {c, +, d}_x  ->  {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x.  */
-  return 
-    build_polynomial_chrec 
-    (CHREC_VARIABLE (poly0), 
-     build_polynomial_chrec 
-     (CHREC_VARIABLE (poly0), 
       
       
-      /* "a*c".  */
-      chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)),
-      
-      /* "a*d + b*c + b*d".  */
-      chrec_fold_plus 
-      (type, chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_RIGHT (poly1)),
-       
-       chrec_fold_plus 
-       (type, 
-       chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_LEFT (poly1)),
-       chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1))))),
-     
-     /* "2*b*d".  */
-     chrec_fold_multiply
-     (type, build_int_cst (NULL_TREE, 2),
-      chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1))));
+  /* "a*c".  */
+  t0 = chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1));
+
+  /* "a*d + b*c".  */
+  t1 = chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_RIGHT (poly1));
+  t1 = chrec_fold_plus (type, t1, chrec_fold_multiply (type,
+                                                      CHREC_RIGHT (poly0),
+                                                      CHREC_LEFT (poly1)));
+  /* "b*d".  */
+  t2 = chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1));
+  /* "a*d + b*c + b*d".  */
+  t1 = chrec_fold_plus (type, t1, t2);
+  /* "2*b*d".  */
+  t2 = chrec_fold_multiply (type, SCALAR_FLOAT_TYPE_P (type)
+                           ? build_real (type, dconst2)
+                           : build_int_cst (type, 2), t2);
+
+  var = CHREC_VARIABLE (poly0);
+  return build_polynomial_chrec (var, t0,
+                                build_polynomial_chrec (var, t1, t2));
 }
 
 /* When the operands are automatically_generated_chrec_p, the fold has
 }
 
 /* When the operands are automatically_generated_chrec_p, the fold has
@@ -248,11 +266,11 @@ chrec_fold_automatically_generated_operands (tree op0,
 /* Fold the addition of two chrecs.  */
 
 static tree
 /* Fold the addition of two chrecs.  */
 
 static tree
-chrec_fold_plus_1 (enum tree_code code, 
-                  tree type, 
-                  tree op0,
-                  tree op1)
+chrec_fold_plus_1 (enum tree_code code, tree type, 
+                  tree op0, tree op1)
 {
 {
+  tree op1_type = code == POINTER_PLUS_EXPR ? sizetype : type;
+
   if (automatically_generated_chrec_p (op0)
       || automatically_generated_chrec_p (op1))
     return chrec_fold_automatically_generated_operands (op0, op1);
   if (automatically_generated_chrec_p (op0)
       || automatically_generated_chrec_p (op1))
     return chrec_fold_automatically_generated_operands (op0, op1);
@@ -266,7 +284,7 @@ chrec_fold_plus_1 (enum tree_code code,
          return chrec_fold_plus_poly_poly (code, type, op0, op1);
 
        default:
          return chrec_fold_plus_poly_poly (code, type, op0, op1);
 
        default:
-         if (code == PLUS_EXPR)
+         if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR)
            return build_polynomial_chrec 
              (CHREC_VARIABLE (op0), 
               chrec_fold_plus (type, CHREC_LEFT (op0), op1),
            return build_polynomial_chrec 
              (CHREC_VARIABLE (op0), 
               chrec_fold_plus (type, CHREC_LEFT (op0), op1),
@@ -282,7 +300,7 @@ chrec_fold_plus_1 (enum tree_code code,
       switch (TREE_CODE (op1))
        {
        case POLYNOMIAL_CHREC:
       switch (TREE_CODE (op1))
        {
        case POLYNOMIAL_CHREC:
-         if (code == PLUS_EXPR)
+         if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR)
            return build_polynomial_chrec 
              (CHREC_VARIABLE (op1), 
               chrec_fold_plus (type, op0, CHREC_LEFT (op1)),
            return build_polynomial_chrec 
              (CHREC_VARIABLE (op1), 
               chrec_fold_plus (type, op0, CHREC_LEFT (op1)),
@@ -292,15 +310,24 @@ chrec_fold_plus_1 (enum tree_code code,
              (CHREC_VARIABLE (op1), 
               chrec_fold_minus (type, op0, CHREC_LEFT (op1)),
               chrec_fold_multiply (type, CHREC_RIGHT (op1), 
              (CHREC_VARIABLE (op1), 
               chrec_fold_minus (type, op0, CHREC_LEFT (op1)),
               chrec_fold_multiply (type, CHREC_RIGHT (op1), 
-                                   convert (type,
-                                            integer_minus_one_node)));
+                                   SCALAR_FLOAT_TYPE_P (type)
+                                   ? build_real (type, dconstm1)
+                                   : build_int_cst_type (type, -1)));
 
        default:
 
        default:
-         if (tree_contains_chrecs (op0)
-             || tree_contains_chrecs (op1))
-           return build (code, type, op0, op1);
-         else
-           return fold (build (code, type, op0, op1));
+         {
+           int size = 0;
+           if ((tree_contains_chrecs (op0, &size)
+                || tree_contains_chrecs (op1, &size))
+               && size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE))
+             return build2 (code, type, op0, op1);
+           else if (size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE))
+             return fold_build2 (code, type,
+                                 fold_convert (type, op0),
+                                 fold_convert (op1_type, op1));
+           else
+             return chrec_dont_know;
+         }
        }
     }
 }
        }
     }
 }
@@ -312,12 +339,22 @@ chrec_fold_plus (tree type,
                 tree op0,
                 tree op1)
 {
                 tree op0,
                 tree op1)
 {
+  enum tree_code code;
+  if (automatically_generated_chrec_p (op0)
+      || automatically_generated_chrec_p (op1))
+    return chrec_fold_automatically_generated_operands (op0, op1);
+
   if (integer_zerop (op0))
   if (integer_zerop (op0))
-    return op1;
+    return chrec_convert (type, op1, NULL);
   if (integer_zerop (op1))
   if (integer_zerop (op1))
-    return op0;
+    return chrec_convert (type, op0, NULL);
+
+  if (POINTER_TYPE_P (type))
+    code = POINTER_PLUS_EXPR;
+  else
+    code = PLUS_EXPR;
   
   
-  return chrec_fold_plus_1 (PLUS_EXPR, type, op0, op1);
+  return chrec_fold_plus_1 (code, type, op0, op1);
 }
 
 /* Fold the subtraction of two chrecs.  */
 }
 
 /* Fold the subtraction of two chrecs.  */
@@ -327,6 +364,10 @@ chrec_fold_minus (tree type,
                  tree op0, 
                  tree op1)
 {
                  tree op0, 
                  tree op1)
 {
+  if (automatically_generated_chrec_p (op0)
+      || automatically_generated_chrec_p (op1))
+    return chrec_fold_automatically_generated_operands (op0, op1);
+
   if (integer_zerop (op1))
     return op0;
   
   if (integer_zerop (op1))
     return op0;
   
@@ -356,7 +397,7 @@ chrec_fold_multiply (tree type,
          if (integer_onep (op1))
            return op0;
          if (integer_zerop (op1))
          if (integer_onep (op1))
            return op0;
          if (integer_zerop (op1))
-           return convert (type, integer_zero_node);
+           return build_int_cst (type, 0);
          
          return build_polynomial_chrec 
            (CHREC_VARIABLE (op0), 
          
          return build_polynomial_chrec 
            (CHREC_VARIABLE (op0), 
@@ -369,7 +410,7 @@ chrec_fold_multiply (tree type,
        return op1;
       
       if (integer_zerop (op0))
        return op1;
       
       if (integer_zerop (op0))
-       return convert (type, integer_zero_node);
+       return build_int_cst (type, 0);
       
       switch (TREE_CODE (op1))
        {
       
       switch (TREE_CODE (op1))
        {
@@ -383,8 +424,8 @@ chrec_fold_multiply (tree type,
          if (integer_onep (op1))
            return op0;
          if (integer_zerop (op1))
          if (integer_onep (op1))
            return op0;
          if (integer_zerop (op1))
-           return convert (type, integer_zero_node);
-         return fold (build (MULT_EXPR, type, op0, op1));
+           return build_int_cst (type, 0);
+         return fold_build2 (MULT_EXPR, type, op0, op1);
        }
     }
 }
        }
     }
 }
@@ -393,63 +434,112 @@ chrec_fold_multiply (tree type,
 
 /* Operations.  */
 
 
 /* Operations.  */
 
-/* The factorial.  */
+/* Evaluate the binomial coefficient.  Return NULL_TREE if the intermediate
+   calculation overflows, otherwise return C(n,k) with type TYPE.  */
+
 static tree 
 static tree 
-tree_fold_factorial (tree f)
+tree_fold_binomial (tree type, tree n, unsigned int k)
 {
 {
-  if (tree_int_cst_sgn (f) <= 0)
-    return integer_one_node;
+  unsigned HOST_WIDE_INT lidx, lnum, ldenom, lres, ldum;
+  HOST_WIDE_INT hidx, hnum, hdenom, hres, hdum;
+  unsigned int i;
+  tree res;
+
+  /* Handle the most frequent cases.  */
+  if (k == 0)
+    return build_int_cst (type, 1);
+  if (k == 1)
+    return fold_convert (type, n);
+
+  /* Check that k <= n.  */
+  if (TREE_INT_CST_HIGH (n) == 0
+      && TREE_INT_CST_LOW (n) < k)
+    return NULL_TREE;
+
+  /* Numerator = n.  */
+  lnum = TREE_INT_CST_LOW (n);
+  hnum = TREE_INT_CST_HIGH (n);
+
+  /* Denominator = 2.  */
+  ldenom = 2;
+  hdenom = 0;
+
+  /* Index = Numerator-1.  */
+  if (lnum == 0)
+    {
+      hidx = hnum - 1;
+      lidx = ~ (unsigned HOST_WIDE_INT) 0;
+    }
   else
   else
-    return fold 
-      (build (MULT_EXPR, integer_type_node, f, 
-             tree_fold_factorial (fold (build (MINUS_EXPR, integer_type_node, 
-                                               f, integer_one_node)))));
-}
+    {
+      hidx = hnum;
+      lidx = lnum - 1;
+    }
 
 
-/* The binomial coefficient.  */
+  /* Numerator = Numerator*Index = n*(n-1).  */
+  if (mul_double (lnum, hnum, lidx, hidx, &lnum, &hnum))
+    return NULL_TREE;
 
 
-static tree 
-tree_fold_binomial (tree n,
-                   tree k)
-{
-  return fold 
-    (build (EXACT_DIV_EXPR, integer_type_node, tree_fold_factorial (n), 
-           fold (build (MULT_EXPR, integer_type_node, 
-                        tree_fold_factorial (k),
-                        tree_fold_factorial 
-                        (fold (build (MINUS_EXPR, integer_type_node, 
-                                      n, k)))))));
+  for (i = 3; i <= k; i++)
+    {
+      /* Index--.  */
+      if (lidx == 0)
+       {
+         hidx--;
+         lidx = ~ (unsigned HOST_WIDE_INT) 0;
+       }
+      else
+        lidx--;
+
+      /* Numerator *= Index.  */
+      if (mul_double (lnum, hnum, lidx, hidx, &lnum, &hnum))
+       return NULL_TREE;
+
+      /* Denominator *= i.  */
+      mul_double (ldenom, hdenom, i, 0, &ldenom, &hdenom);
+    }
+
+  /* Result = Numerator / Denominator.  */
+  div_and_round_double (EXACT_DIV_EXPR, 1, lnum, hnum, ldenom, hdenom,
+                       &lres, &hres, &ldum, &hdum);
+
+  res = build_int_cst_wide (type, lres, hres);
+  return int_fits_type_p (res, type) ? res : NULL_TREE;
 }
 
 /* Helper function.  Use the Newton's interpolating formula for
    evaluating the value of the evolution function.  */
 
 static tree 
 }
 
 /* Helper function.  Use the Newton's interpolating formula for
    evaluating the value of the evolution function.  */
 
 static tree 
-chrec_evaluate (unsigned var,
-               tree chrec,
-               tree n,
-               tree k)
+chrec_evaluate (unsigned var, tree chrec, tree n, unsigned int k)
 {
 {
-  tree type = chrec_type (chrec);
-  tree binomial_n_k = tree_fold_binomial (n, k);
-  
-  if (TREE_CODE (chrec) == POLYNOMIAL_CHREC)
+  tree arg0, arg1, binomial_n_k;
+  tree type = TREE_TYPE (chrec);
+  struct loop *var_loop = get_loop (var);
+
+  while (TREE_CODE (chrec) == POLYNOMIAL_CHREC
+        && flow_loop_nested_p (var_loop, get_chrec_loop (chrec)))
+    chrec = CHREC_LEFT (chrec);
+
+  if (TREE_CODE (chrec) == POLYNOMIAL_CHREC
+      && CHREC_VARIABLE (chrec) == var)
     {
     {
-      if (CHREC_VARIABLE (chrec) > var)
-       return chrec_evaluate (var, CHREC_LEFT (chrec), n, k);
-      
-      if (CHREC_VARIABLE (chrec) == var)
-       return chrec_fold_plus 
-         (type, 
-          fold (build (MULT_EXPR, type, binomial_n_k, CHREC_LEFT (chrec))),
-          chrec_evaluate (var, CHREC_RIGHT (chrec), n, 
-                          fold (build (PLUS_EXPR, type, k, integer_one_node))));
-      
-      return fold (build (MULT_EXPR, type, binomial_n_k, chrec));
+      arg1 = chrec_evaluate (var, CHREC_RIGHT (chrec), n, k + 1);
+      if (arg1 == chrec_dont_know)
+       return chrec_dont_know;
+      binomial_n_k = tree_fold_binomial (type, n, k);
+      if (!binomial_n_k)
+       return chrec_dont_know;
+      arg0 = fold_build2 (MULT_EXPR, type,
+                         CHREC_LEFT (chrec), binomial_n_k);
+      return chrec_fold_plus (type, arg0, arg1);
     }
     }
-  else
-    return fold (build (MULT_EXPR, type, binomial_n_k, chrec));
+
+  binomial_n_k = tree_fold_binomial (type, n, k);
+  if (!binomial_n_k)
+    return chrec_dont_know;
+  
+  return fold_build2 (MULT_EXPR, type, chrec, binomial_n_k);
 }
 
 /* Evaluates "CHREC (X)" when the varying variable is VAR.  
 }
 
 /* Evaluates "CHREC (X)" when the varying variable is VAR.  
@@ -477,24 +567,21 @@ chrec_apply (unsigned var,
       /* When the symbols are defined in an outer loop, it is possible
         to symbolically compute the apply, since the symbols are
         constants with respect to the varying loop.  */
       /* When the symbols are defined in an outer loop, it is possible
         to symbolically compute the apply, since the symbols are
         constants with respect to the varying loop.  */
-      || chrec_contains_symbols_defined_in_loop (chrec, var)
-      || chrec_contains_symbols (x))
+      || chrec_contains_symbols_defined_in_loop (chrec, var))
     return chrec_dont_know;
     return chrec_dont_know;
-  
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "(chrec_apply \n");
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "(chrec_apply \n");
 
+  if (TREE_CODE (x) == INTEGER_CST && SCALAR_FLOAT_TYPE_P (type))
+    x = build_real_from_int_cst (type, x);
+
   if (evolution_function_is_affine_p (chrec))
     {
       /* "{a, +, b} (x)"  ->  "a + b*x".  */
   if (evolution_function_is_affine_p (chrec))
     {
       /* "{a, +, b} (x)"  ->  "a + b*x".  */
-      if (TREE_CODE (CHREC_LEFT (chrec)) == INTEGER_CST
-         && integer_zerop (CHREC_LEFT (chrec)))
-       res = chrec_fold_multiply (type, CHREC_RIGHT (chrec), x);
-      
-      else
-       res = chrec_fold_plus (type, CHREC_LEFT (chrec), 
-                              chrec_fold_multiply (type, 
-                                                   CHREC_RIGHT (chrec), x));
+      x = chrec_convert_rhs (type, x, NULL);
+      res = chrec_fold_multiply (TREE_TYPE (x), CHREC_RIGHT (chrec), x);
+      res = chrec_fold_plus (type, CHREC_LEFT (chrec), res);
     }
   
   else if (TREE_CODE (chrec) != POLYNOMIAL_CHREC)
     }
   
   else if (TREE_CODE (chrec) != POLYNOMIAL_CHREC)
@@ -503,8 +590,7 @@ chrec_apply (unsigned var,
   else if (TREE_CODE (x) == INTEGER_CST
           && tree_int_cst_sgn (x) == 1)
     /* testsuite/.../ssa-chrec-38.c.  */
   else if (TREE_CODE (x) == INTEGER_CST
           && tree_int_cst_sgn (x) == 1)
     /* testsuite/.../ssa-chrec-38.c.  */
-    res = chrec_evaluate (var, chrec, x, integer_zero_node);
-
+    res = chrec_evaluate (var, chrec, x, 0);
   else
     res = chrec_dont_know;
   
   else
     res = chrec_dont_know;
   
@@ -531,7 +617,9 @@ chrec_replace_initial_condition (tree chrec,
 {
   if (automatically_generated_chrec_p (chrec))
     return chrec;
 {
   if (automatically_generated_chrec_p (chrec))
     return chrec;
-  
+
+  gcc_assert (chrec_type (chrec) == chrec_type (init_cond));
+
   switch (TREE_CODE (chrec))
     {
     case POLYNOMIAL_CHREC:
   switch (TREE_CODE (chrec))
     {
     case POLYNOMIAL_CHREC:
@@ -566,71 +654,119 @@ tree
 hide_evolution_in_other_loops_than_loop (tree chrec, 
                                         unsigned loop_num)
 {
 hide_evolution_in_other_loops_than_loop (tree chrec, 
                                         unsigned loop_num)
 {
+  struct loop *loop = get_loop (loop_num), *chloop;
   if (automatically_generated_chrec_p (chrec))
     return chrec;
   
   switch (TREE_CODE (chrec))
     {
     case POLYNOMIAL_CHREC:
   if (automatically_generated_chrec_p (chrec))
     return chrec;
   
   switch (TREE_CODE (chrec))
     {
     case POLYNOMIAL_CHREC:
-      if (CHREC_VARIABLE (chrec) == loop_num)
+      chloop = get_chrec_loop (chrec);
+
+      if (chloop == loop)
        return build_polynomial_chrec 
          (loop_num, 
           hide_evolution_in_other_loops_than_loop (CHREC_LEFT (chrec), 
                                                    loop_num), 
           CHREC_RIGHT (chrec));
       
        return build_polynomial_chrec 
          (loop_num, 
           hide_evolution_in_other_loops_than_loop (CHREC_LEFT (chrec), 
                                                    loop_num), 
           CHREC_RIGHT (chrec));
       
-      else if (CHREC_VARIABLE (chrec) < loop_num)
+      else if (flow_loop_nested_p (chloop, loop))
        /* There is no evolution in this loop.  */
        return initial_condition (chrec);
       
       else
        /* There is no evolution in this loop.  */
        return initial_condition (chrec);
       
       else
-       return hide_evolution_in_other_loops_than_loop (CHREC_LEFT (chrec), 
-                                                       loop_num);
+       {
+         gcc_assert (flow_loop_nested_p (loop, chloop));
+         return hide_evolution_in_other_loops_than_loop (CHREC_LEFT (chrec), 
+                                                         loop_num);
+       }
       
     default:
       return chrec;
     }
 }
 
       
     default:
       return chrec;
     }
 }
 
-/* Returns the evolution part in LOOP_NUM.  Example: the call
-   get_evolution_in_loop (1, {{0, +, 1}_1, +, 2}_1) returns 
-   {1, +, 2}_1  */
+/* Returns the evolution part of CHREC in LOOP_NUM when RIGHT is
+   true, otherwise returns the initial condition in LOOP_NUM.  */
 
 
-tree 
-evolution_part_in_loop_num (tree chrec, 
-                           unsigned loop_num)
+static tree 
+chrec_component_in_loop_num (tree chrec, 
+                            unsigned loop_num,
+                            bool right)
 {
 {
+  tree component;
+  struct loop *loop = get_loop (loop_num), *chloop;
+
   if (automatically_generated_chrec_p (chrec))
     return chrec;
   
   switch (TREE_CODE (chrec))
     {
     case POLYNOMIAL_CHREC:
   if (automatically_generated_chrec_p (chrec))
     return chrec;
   
   switch (TREE_CODE (chrec))
     {
     case POLYNOMIAL_CHREC:
-      if (CHREC_VARIABLE (chrec) == loop_num)
+      chloop = get_chrec_loop (chrec);
+
+      if (chloop == loop)
        {
        {
+         if (right)
+           component = CHREC_RIGHT (chrec);
+         else
+           component = CHREC_LEFT (chrec);
+
          if (TREE_CODE (CHREC_LEFT (chrec)) != POLYNOMIAL_CHREC
              || CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec))
          if (TREE_CODE (CHREC_LEFT (chrec)) != POLYNOMIAL_CHREC
              || CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec))
-           return CHREC_RIGHT (chrec);
+           return component;
          
          else
            return build_polynomial_chrec
              (loop_num, 
          
          else
            return build_polynomial_chrec
              (loop_num, 
-              evolution_part_in_loop_num (CHREC_LEFT (chrec), loop_num), 
-              CHREC_RIGHT (chrec));
+              chrec_component_in_loop_num (CHREC_LEFT (chrec), 
+                                           loop_num, 
+                                           right), 
+              component);
        }
       
        }
       
-      else if (CHREC_VARIABLE (chrec) < loop_num)
+      else if (flow_loop_nested_p (chloop, loop))
        /* There is no evolution part in this loop.  */
        return NULL_TREE;
       
       else
        /* There is no evolution part in this loop.  */
        return NULL_TREE;
       
       else
-       return evolution_part_in_loop_num (CHREC_LEFT (chrec), loop_num);
+       {
+         gcc_assert (flow_loop_nested_p (loop, chloop));
+         return chrec_component_in_loop_num (CHREC_LEFT (chrec), 
+                                             loop_num, 
+                                             right);
+       }
       
       
-    default:
-      return NULL_TREE;
+     default:
+      if (right)
+       return NULL_TREE;
+      else
+       return chrec;
     }
 }
 
     }
 }
 
+/* Returns the evolution part in LOOP_NUM.  Example: the call
+   evolution_part_in_loop_num ({{0, +, 1}_1, +, 2}_1, 1) returns 
+   {1, +, 2}_1  */
+
+tree 
+evolution_part_in_loop_num (tree chrec, 
+                           unsigned loop_num)
+{
+  return chrec_component_in_loop_num (chrec, loop_num, true);
+}
+
+/* Returns the initial condition in LOOP_NUM.  Example: the call
+   initial_condition_in_loop_num ({{0, +, 1}_1, +, 2}_2, 2) returns 
+   {0, +, 1}_1  */
+
+tree 
+initial_condition_in_loop_num (tree chrec, 
+                              unsigned loop_num)
+{
+  return chrec_component_in_loop_num (chrec, loop_num, false);
+}
+
 /* Set or reset the evolution of CHREC to NEW_EVOL in loop LOOP_NUM.
    This function is essentially used for setting the evolution to
    chrec_dont_know, for example after having determined that it is
 /* Set or reset the evolution of CHREC to NEW_EVOL in loop LOOP_NUM.
    This function is essentially used for setting the evolution to
    chrec_dont_know, for example after having determined that it is
@@ -641,14 +777,25 @@ reset_evolution_in_loop (unsigned loop_num,
                         tree chrec, 
                         tree new_evol)
 {
                         tree chrec, 
                         tree new_evol)
 {
+  struct loop *loop = get_loop (loop_num);
+
+  if (POINTER_TYPE_P (chrec_type (chrec)))
+    gcc_assert (sizetype == chrec_type (new_evol));
+  else
+    gcc_assert (chrec_type (chrec) == chrec_type (new_evol));
+
   if (TREE_CODE (chrec) == POLYNOMIAL_CHREC
   if (TREE_CODE (chrec) == POLYNOMIAL_CHREC
-      && CHREC_VARIABLE (chrec) > loop_num)
-    return build 
-      (TREE_CODE (chrec), 
-       build_int_cst (NULL_TREE, CHREC_VARIABLE (chrec)), 
-       reset_evolution_in_loop (loop_num, CHREC_LEFT (chrec), new_evol), 
-       reset_evolution_in_loop (loop_num, CHREC_RIGHT (chrec), new_evol));
-  
+      && flow_loop_nested_p (loop, get_chrec_loop (chrec)))
+    {
+      tree left = reset_evolution_in_loop (loop_num, CHREC_LEFT (chrec),
+                                          new_evol);
+      tree right = reset_evolution_in_loop (loop_num, CHREC_RIGHT (chrec),
+                                           new_evol);
+      return build3 (POLYNOMIAL_CHREC, TREE_TYPE (left),
+                    build_int_cst (NULL_TREE, CHREC_VARIABLE (chrec)),
+                    left, right);
+    }
+
   while (TREE_CODE (chrec) == POLYNOMIAL_CHREC
         && CHREC_VARIABLE (chrec) == loop_num)
     chrec = CHREC_LEFT (chrec);
   while (TREE_CODE (chrec) == POLYNOMIAL_CHREC
         && CHREC_VARIABLE (chrec) == loop_num)
     chrec = CHREC_LEFT (chrec);
@@ -676,7 +823,7 @@ chrec_merge (tree chrec1,
   if (chrec2 == chrec_not_analyzed_yet)
     return chrec1;
 
   if (chrec2 == chrec_not_analyzed_yet)
     return chrec1;
 
-  if (operand_equal_p (chrec1, chrec2, 0))
+  if (eq_evolutions_p (chrec1, chrec2))
     return chrec1;
 
   return chrec_dont_know;
     return chrec1;
 
   return chrec_dont_know;
@@ -689,7 +836,7 @@ chrec_merge (tree chrec1,
 /* Helper function for is_multivariate_chrec.  */
 
 static bool 
 /* Helper function for is_multivariate_chrec.  */
 
 static bool 
-is_multivariate_chrec_rec (tree chrec, unsigned int rec_var)
+is_multivariate_chrec_rec (const_tree chrec, unsigned int rec_var)
 {
   if (chrec == NULL_TREE)
     return false;
 {
   if (chrec == NULL_TREE)
     return false;
@@ -709,7 +856,7 @@ is_multivariate_chrec_rec (tree chrec, unsigned int rec_var)
 /* Determine whether the given chrec is multivariate or not.  */
 
 bool 
 /* Determine whether the given chrec is multivariate or not.  */
 
 bool 
-is_multivariate_chrec (tree chrec)
+is_multivariate_chrec (const_tree chrec)
 {
   if (chrec == NULL_TREE)
     return false;
 {
   if (chrec == NULL_TREE)
     return false;
@@ -726,8 +873,10 @@ is_multivariate_chrec (tree chrec)
 /* Determines whether the chrec contains symbolic names or not.  */
 
 bool 
 /* Determines whether the chrec contains symbolic names or not.  */
 
 bool 
-chrec_contains_symbols (tree chrec)
+chrec_contains_symbols (const_tree chrec)
 {
 {
+  int i, n;
+
   if (chrec == NULL_TREE)
     return false;
   
   if (chrec == NULL_TREE)
     return false;
   
@@ -739,90 +888,116 @@ chrec_contains_symbols (tree chrec)
       || TREE_CODE (chrec) == RESULT_DECL
       || TREE_CODE (chrec) == FIELD_DECL)
     return true;
       || TREE_CODE (chrec) == RESULT_DECL
       || TREE_CODE (chrec) == FIELD_DECL)
     return true;
-  
-  switch (TREE_CODE_LENGTH (TREE_CODE (chrec)))
-    {
-    case 3:
-      if (chrec_contains_symbols (TREE_OPERAND (chrec, 2)))
-       return true;
-      
-    case 2:
-      if (chrec_contains_symbols (TREE_OPERAND (chrec, 1)))
-       return true;
-      
-    case 1:
-      if (chrec_contains_symbols (TREE_OPERAND (chrec, 0)))
-       return true;
-      
-    default:
-      return false;
-    }
+
+  n = TREE_OPERAND_LENGTH (chrec);
+  for (i = 0; i < n; i++)
+    if (chrec_contains_symbols (TREE_OPERAND (chrec, i)))
+      return true;
+  return false;
 }
 
 /* Determines whether the chrec contains undetermined coefficients.  */
 
 bool 
 }
 
 /* Determines whether the chrec contains undetermined coefficients.  */
 
 bool 
-chrec_contains_undetermined (tree chrec)
+chrec_contains_undetermined (const_tree chrec)
 {
 {
-  if (chrec == chrec_dont_know
-      || chrec == chrec_not_analyzed_yet
-      || chrec == NULL_TREE)
+  int i, n;
+
+  if (chrec == chrec_dont_know)
     return true;
     return true;
-  
-  switch (TREE_CODE_LENGTH (TREE_CODE (chrec)))
-    {
-    case 3:
-      if (chrec_contains_undetermined (TREE_OPERAND (chrec, 2)))
-       return true;
-      
-    case 2:
-      if (chrec_contains_undetermined (TREE_OPERAND (chrec, 1)))
-       return true;
-      
-    case 1:
-      if (chrec_contains_undetermined (TREE_OPERAND (chrec, 0)))
-       return true;
-      
-    default:
-      return false;
-    }
+
+  if (chrec == NULL_TREE)
+    return false;
+
+  n = TREE_OPERAND_LENGTH (chrec);
+  for (i = 0; i < n; i++)
+    if (chrec_contains_undetermined (TREE_OPERAND (chrec, i)))
+      return true;
+  return false;
 }
 
 }
 
-/* Determines whether the tree EXPR contains chrecs.  */
+/* Determines whether the tree EXPR contains chrecs, and increment
+   SIZE if it is not a NULL pointer by an estimation of the depth of
+   the tree.  */
 
 bool
 
 bool
-tree_contains_chrecs (tree expr)
+tree_contains_chrecs (const_tree expr, int *size)
 {
 {
+  int i, n;
+
   if (expr == NULL_TREE)
     return false;
   if (expr == NULL_TREE)
     return false;
+
+  if (size)
+    (*size)++;
   
   if (tree_is_chrec (expr))
     return true;
   
   if (tree_is_chrec (expr))
     return true;
-  
-  switch (TREE_CODE_LENGTH (TREE_CODE (expr)))
+
+  n = TREE_OPERAND_LENGTH (expr);
+  for (i = 0; i < n; i++)
+    if (tree_contains_chrecs (TREE_OPERAND (expr, i), size))
+      return true;
+  return false;
+}
+
+/* Recursive helper function.  */
+
+static bool
+evolution_function_is_invariant_rec_p (tree chrec, int loopnum)
+{
+  if (evolution_function_is_constant_p (chrec))
+    return true;
+
+  if (TREE_CODE (chrec) == SSA_NAME
+      && (loopnum == 0
+         || expr_invariant_in_loop_p (get_loop (loopnum), chrec)))
+    return true;
+
+  if (TREE_CODE (chrec) == POLYNOMIAL_CHREC)
+    {
+      if (CHREC_VARIABLE (chrec) == (unsigned) loopnum
+         || !evolution_function_is_invariant_rec_p (CHREC_RIGHT (chrec),
+                                                    loopnum)
+         || !evolution_function_is_invariant_rec_p (CHREC_LEFT (chrec),
+                                                    loopnum))
+       return false;
+      return true;
+    }
+
+  switch (TREE_OPERAND_LENGTH (chrec))
     {
     {
-    case 3:
-      if (tree_contains_chrecs (TREE_OPERAND (expr, 2)))
-       return true;
-      
     case 2:
     case 2:
-      if (tree_contains_chrecs (TREE_OPERAND (expr, 1)))
-       return true;
+      if (!evolution_function_is_invariant_rec_p (TREE_OPERAND (chrec, 1),
+                                                 loopnum))
+       return false;
       
     case 1:
       
     case 1:
-      if (tree_contains_chrecs (TREE_OPERAND (expr, 0)))
-       return true;
-      
+      if (!evolution_function_is_invariant_rec_p (TREE_OPERAND (chrec, 0),
+                                                 loopnum))
+       return false;
+      return true;
+
     default:
       return false;
     }
     default:
       return false;
     }
+
+  return false;
+}
+
+/* Return true if CHREC is invariant in loop LOOPNUM, false otherwise. */
+
+bool
+evolution_function_is_invariant_p (tree chrec, int loopnum)
+{
+  return evolution_function_is_invariant_rec_p (chrec, loopnum);
 }
 
 /* Determine whether the given tree is an affine multivariate
    evolution.  */
 
 bool 
 }
 
 /* Determine whether the given tree is an affine multivariate
    evolution.  */
 
 bool 
-evolution_function_is_affine_multivariate_p (tree chrec)
+evolution_function_is_affine_multivariate_p (const_tree chrec, int loopnum)
 {
   if (chrec == NULL_TREE)
     return false;
 {
   if (chrec == NULL_TREE)
     return false;
@@ -830,9 +1005,9 @@ evolution_function_is_affine_multivariate_p (tree chrec)
   switch (TREE_CODE (chrec))
     {
     case POLYNOMIAL_CHREC:
   switch (TREE_CODE (chrec))
     {
     case POLYNOMIAL_CHREC:
-      if (evolution_function_is_constant_p (CHREC_LEFT (chrec)))
+      if (evolution_function_is_invariant_rec_p (CHREC_LEFT (chrec), loopnum))
        {
        {
-         if (evolution_function_is_constant_p (CHREC_RIGHT (chrec)))
+         if (evolution_function_is_invariant_rec_p (CHREC_RIGHT (chrec), loopnum))
            return true;
          else
            {
            return true;
          else
            {
@@ -840,7 +1015,7 @@ evolution_function_is_affine_multivariate_p (tree chrec)
                  && CHREC_VARIABLE (CHREC_RIGHT (chrec)) 
                     != CHREC_VARIABLE (chrec)
                  && evolution_function_is_affine_multivariate_p 
                  && CHREC_VARIABLE (CHREC_RIGHT (chrec)) 
                     != CHREC_VARIABLE (chrec)
                  && evolution_function_is_affine_multivariate_p 
-                 (CHREC_RIGHT (chrec)))
+                 (CHREC_RIGHT (chrec), loopnum))
                return true;
              else
                return false;
                return true;
              else
                return false;
@@ -848,11 +1023,11 @@ evolution_function_is_affine_multivariate_p (tree chrec)
        }
       else
        {
        }
       else
        {
-         if (evolution_function_is_constant_p (CHREC_RIGHT (chrec))
+         if (evolution_function_is_invariant_rec_p (CHREC_RIGHT (chrec), loopnum)
              && TREE_CODE (CHREC_LEFT (chrec)) == POLYNOMIAL_CHREC
              && CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec)
              && evolution_function_is_affine_multivariate_p 
              && TREE_CODE (CHREC_LEFT (chrec)) == POLYNOMIAL_CHREC
              && CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec)
              && evolution_function_is_affine_multivariate_p 
-             (CHREC_LEFT (chrec)))
+             (CHREC_LEFT (chrec), loopnum))
            return true;
          else
            return false;
            return true;
          else
            return false;
@@ -867,7 +1042,7 @@ evolution_function_is_affine_multivariate_p (tree chrec)
    variables.  */
 
 bool
    variables.  */
 
 bool
-evolution_function_is_univariate_p (tree chrec)
+evolution_function_is_univariate_p (const_tree chrec)
 {
   if (chrec == NULL_TREE)
     return true;
 {
   if (chrec == NULL_TREE)
     return true;
@@ -906,16 +1081,192 @@ evolution_function_is_univariate_p (tree chrec)
     }
 }
 
     }
 }
 
+/* Returns the number of variables of CHREC.  Example: the call
+   nb_vars_in_chrec ({{0, +, 1}_5, +, 2}_6) returns 2.  */
+
+unsigned 
+nb_vars_in_chrec (tree chrec)
+{
+  if (chrec == NULL_TREE)
+    return 0;
+
+  switch (TREE_CODE (chrec))
+    {
+    case POLYNOMIAL_CHREC:
+      return 1 + nb_vars_in_chrec 
+       (initial_condition_in_loop_num (chrec, CHREC_VARIABLE (chrec)));
+
+    default:
+      return 0;
+    }
+}
+
+static tree chrec_convert_1 (tree, tree, gimple, bool);
+
+/* Converts BASE and STEP of affine scev to TYPE.  LOOP is the loop whose iv
+   the scev corresponds to.  AT_STMT is the statement at that the scev is
+   evaluated.  USE_OVERFLOW_SEMANTICS is true if this function should assume that
+   the rules for overflow of the given language apply (e.g., that signed
+   arithmetics in C does not overflow) -- i.e., to use them to avoid unnecessary
+   tests, but also to enforce that the result follows them.  Returns true if the
+   conversion succeeded, false otherwise.  */
+
+bool
+convert_affine_scev (struct loop *loop, tree type,
+                    tree *base, tree *step, gimple at_stmt,
+                    bool use_overflow_semantics)
+{
+  tree ct = TREE_TYPE (*step);
+  bool enforce_overflow_semantics;
+  bool must_check_src_overflow, must_check_rslt_overflow;
+  tree new_base, new_step;
+  tree step_type = POINTER_TYPE_P (type) ? sizetype : type;
+
+  /* In general,
+     (TYPE) (BASE + STEP * i) = (TYPE) BASE + (TYPE -- sign extend) STEP * i,
+     but we must check some assumptions.
+     
+     1) If [BASE, +, STEP] wraps, the equation is not valid when precision
+        of CT is smaller than the precision of TYPE.  For example, when we
+       cast unsigned char [254, +, 1] to unsigned, the values on left side
+       are 254, 255, 0, 1, ..., but those on the right side are
+       254, 255, 256, 257, ...
+     2) In case that we must also preserve the fact that signed ivs do not
+        overflow, we must additionally check that the new iv does not wrap.
+       For example, unsigned char [125, +, 1] casted to signed char could
+       become a wrapping variable with values 125, 126, 127, -128, -127, ...,
+       which would confuse optimizers that assume that this does not
+       happen.  */
+  must_check_src_overflow = TYPE_PRECISION (ct) < TYPE_PRECISION (type);
+
+  enforce_overflow_semantics = (use_overflow_semantics
+                               && nowrap_type_p (type));
+  if (enforce_overflow_semantics)
+    {
+      /* We can avoid checking whether the result overflows in the following
+        cases:
+
+        -- must_check_src_overflow is true, and the range of TYPE is superset
+           of the range of CT -- i.e., in all cases except if CT signed and
+           TYPE unsigned.
+         -- both CT and TYPE have the same precision and signedness, and we
+           verify instead that the source does not overflow (this may be
+           easier than verifying it for the result, as we may use the
+           information about the semantics of overflow in CT).  */
+      if (must_check_src_overflow)
+       {
+         if (TYPE_UNSIGNED (type) && !TYPE_UNSIGNED (ct))
+           must_check_rslt_overflow = true;
+         else
+           must_check_rslt_overflow = false;
+       }
+      else if (TYPE_UNSIGNED (ct) == TYPE_UNSIGNED (type)
+              && TYPE_PRECISION (ct) == TYPE_PRECISION (type))
+       {
+         must_check_rslt_overflow = false;
+         must_check_src_overflow = true;
+       }
+      else
+       must_check_rslt_overflow = true;
+    }
+  else
+    must_check_rslt_overflow = false;
+
+  if (must_check_src_overflow
+      && scev_probably_wraps_p (*base, *step, at_stmt, loop,
+                               use_overflow_semantics))
+    return false;
+
+  new_base = chrec_convert_1 (type, *base, at_stmt,
+                             use_overflow_semantics);
+  /* The step must be sign extended, regardless of the signedness
+     of CT and TYPE.  This only needs to be handled specially when
+     CT is unsigned -- to avoid e.g. unsigned char [100, +, 255]
+     (with values 100, 99, 98, ...) from becoming signed or unsigned
+     [100, +, 255] with values 100, 355, ...; the sign-extension is 
+     performed by default when CT is signed.  */
+  new_step = *step;
+  if (TYPE_PRECISION (step_type) > TYPE_PRECISION (ct) && TYPE_UNSIGNED (ct))
+    new_step = chrec_convert_1 (signed_type_for (ct), new_step, at_stmt,
+                               use_overflow_semantics);
+  new_step = chrec_convert_1 (step_type, new_step, at_stmt, use_overflow_semantics);
+
+  if (automatically_generated_chrec_p (new_base)
+      || automatically_generated_chrec_p (new_step))
+    return false;
+
+  if (must_check_rslt_overflow
+      /* Note that in this case we cannot use the fact that signed variables
+        do not overflow, as this is what we are verifying for the new iv.  */
+      && scev_probably_wraps_p (new_base, new_step, at_stmt, loop, false))
+    return false;
+
+  *base = new_base;
+  *step = new_step;
+  return true;
+}
 \f
 
 \f
 
-/* Convert the initial condition of chrec to type.  */
+/* Convert CHREC for the right hand side of a CREC.
+   The increment for a pointer type is always sizetype.  */
+tree 
+chrec_convert_rhs (tree type, tree chrec, gimple at_stmt)
+{
+  if (POINTER_TYPE_P (type))
+   type = sizetype;
+  return chrec_convert (type, chrec, at_stmt);
+}
+
+/* Convert CHREC to TYPE.  When the analyzer knows the context in
+   which the CHREC is built, it sets AT_STMT to the statement that
+   contains the definition of the analyzed variable, otherwise the
+   conversion is less accurate: the information is used for
+   determining a more accurate estimation of the number of iterations.
+   By default AT_STMT could be safely set to NULL_TREE.
+
+   The following rule is always true: TREE_TYPE (chrec) ==
+   TREE_TYPE (CHREC_LEFT (chrec)) == TREE_TYPE (CHREC_RIGHT (chrec)).
+   An example of what could happen when adding two chrecs and the type
+   of the CHREC_RIGHT is different than CHREC_LEFT is:
+   
+   {(uint) 0, +, (uchar) 10} +
+   {(uint) 0, +, (uchar) 250}
+   
+   that would produce a wrong result if CHREC_RIGHT is not (uint):
+   
+   {(uint) 0, +, (uchar) 4}
+
+   instead of
+
+   {(uint) 0, +, (uint) 260}
+*/
 
 tree 
 
 tree 
-chrec_convert (tree type, 
-              tree chrec)
+chrec_convert (tree type, tree chrec, gimple at_stmt)
 {
 {
-  tree ct;
-  
+  return chrec_convert_1 (type, chrec, at_stmt, true);
+}
+
+/* Convert CHREC to TYPE.  When the analyzer knows the context in
+   which the CHREC is built, it sets AT_STMT to the statement that
+   contains the definition of the analyzed variable, otherwise the
+   conversion is less accurate: the information is used for
+   determining a more accurate estimation of the number of iterations.
+   By default AT_STMT could be safely set to NULL_TREE.
+   USE_OVERFLOW_SEMANTICS is true if this function should assume that
+   the rules for overflow of the given language apply (e.g., that signed
+   arithmetics in C does not overflow) -- i.e., to use them to avoid unnecessary
+   tests, but also to enforce that the result follows them.  */
+
+static tree 
+chrec_convert_1 (tree type, tree chrec, gimple at_stmt,
+                bool use_overflow_semantics)
+{
+  tree ct, res;
+  tree base, step;
+  struct loop *loop;
+
   if (automatically_generated_chrec_p (chrec))
     return chrec;
   
   if (automatically_generated_chrec_p (chrec))
     return chrec;
   
@@ -923,56 +1274,246 @@ chrec_convert (tree type,
   if (ct == type)
     return chrec;
 
   if (ct == type)
     return chrec;
 
-  if (TYPE_PRECISION (ct) < TYPE_PRECISION (type))
-    return count_ev_in_wider_type (type, chrec);
+  if (!evolution_function_is_affine_p (chrec))
+    goto keep_cast;
+
+  loop = get_chrec_loop (chrec);
+  base = CHREC_LEFT (chrec);
+  step = CHREC_RIGHT (chrec);
+
+  if (convert_affine_scev (loop, type, &base, &step, at_stmt,
+                          use_overflow_semantics))
+    return build_polynomial_chrec (loop->num, base, step);
+
+  /* If we cannot propagate the cast inside the chrec, just keep the cast.  */
+keep_cast:
+  /* Fold will not canonicalize (long)(i - 1) to (long)i - 1 because that
+     may be more expensive.  We do want to perform this optimization here
+     though for canonicalization reasons.  */
+  if (use_overflow_semantics
+      && (TREE_CODE (chrec) == PLUS_EXPR
+         || TREE_CODE (chrec) == MINUS_EXPR)
+      && TYPE_PRECISION (type) > TYPE_PRECISION (ct)
+      && TYPE_OVERFLOW_UNDEFINED (ct))
+    res = fold_build2 (TREE_CODE (chrec), type,
+                      fold_convert (type, TREE_OPERAND (chrec, 0)),
+                      fold_convert (type, TREE_OPERAND (chrec, 1)));
+  else
+    res = fold_convert (type, chrec);
+
+  /* Don't propagate overflows.  */
+  if (CONSTANT_CLASS_P (res))
+    TREE_OVERFLOW (res) = 0;
+
+  /* But reject constants that don't fit in their type after conversion.
+     This can happen if TYPE_MIN_VALUE or TYPE_MAX_VALUE are not the
+     natural values associated with TYPE_PRECISION and TYPE_UNSIGNED,
+     and can cause problems later when computing niters of loops.  Note
+     that we don't do the check before converting because we don't want
+     to reject conversions of negative chrecs to unsigned types.  */
+  if (TREE_CODE (res) == INTEGER_CST
+      && TREE_CODE (type) == INTEGER_TYPE
+      && !int_fits_type_p (res, type))
+    res = chrec_dont_know;
 
 
-  switch (TREE_CODE (chrec))
+  return res;
+}
+
+/* Convert CHREC to TYPE, without regard to signed overflows.  Returns the new
+   chrec if something else than what chrec_convert would do happens, NULL_TREE
+   otherwise.  */
+
+tree
+chrec_convert_aggressive (tree type, tree chrec)
+{
+  tree inner_type, left, right, lc, rc, rtype;
+
+  if (automatically_generated_chrec_p (chrec)
+      || TREE_CODE (chrec) != POLYNOMIAL_CHREC)
+    return NULL_TREE;
+
+  inner_type = TREE_TYPE (chrec);
+  if (TYPE_PRECISION (type) > TYPE_PRECISION (inner_type))
+    return NULL_TREE;
+
+  rtype = POINTER_TYPE_P (type) ? sizetype : type;
+
+  left = CHREC_LEFT (chrec);
+  right = CHREC_RIGHT (chrec);
+  lc = chrec_convert_aggressive (type, left);
+  if (!lc)
+    lc = chrec_convert (type, left, NULL);
+  rc = chrec_convert_aggressive (rtype, right);
+  if (!rc)
+    rc = chrec_convert (rtype, right, NULL);
+  return build_polynomial_chrec (CHREC_VARIABLE (chrec), lc, rc);
+}
+
+/* Returns true when CHREC0 == CHREC1.  */
+
+bool 
+eq_evolutions_p (const_tree chrec0, const_tree chrec1)
+{
+  if (chrec0 == NULL_TREE
+      || chrec1 == NULL_TREE
+      || TREE_CODE (chrec0) != TREE_CODE (chrec1))
+    return false;
+
+  if (chrec0 == chrec1)
+    return true;
+
+  switch (TREE_CODE (chrec0))
     {
     {
+    case INTEGER_CST:
+      return operand_equal_p (chrec0, chrec1, 0);
+
     case POLYNOMIAL_CHREC:
     case POLYNOMIAL_CHREC:
-      return build_polynomial_chrec (CHREC_VARIABLE (chrec),
-                                    chrec_convert (type,
-                                                   CHREC_LEFT (chrec)),
-                                    chrec_convert (type,
-                                                   CHREC_RIGHT (chrec)));
+      return (CHREC_VARIABLE (chrec0) == CHREC_VARIABLE (chrec1)
+             && eq_evolutions_p (CHREC_LEFT (chrec0), CHREC_LEFT (chrec1))
+             && eq_evolutions_p (CHREC_RIGHT (chrec0), CHREC_RIGHT (chrec1)));
+    default:
+      return false;
+    }  
+}
+
+/* Returns EV_GROWS if CHREC grows (assuming that it does not overflow),
+   EV_DECREASES if it decreases, and EV_UNKNOWN if we cannot determine
+   which of these cases happens.  */
+
+enum ev_direction
+scev_direction (const_tree chrec)
+{
+  const_tree step;
+
+  if (!evolution_function_is_affine_p (chrec))
+    return EV_DIR_UNKNOWN;
+
+  step = CHREC_RIGHT (chrec);
+  if (TREE_CODE (step) != INTEGER_CST)
+    return EV_DIR_UNKNOWN;
+
+  if (tree_int_cst_sign_bit (step))
+    return EV_DIR_DECREASES;
+  else
+    return EV_DIR_GROWS;
+}
+
+/* Iterates over all the components of SCEV, and calls CBCK.  */
+
+void
+for_each_scev_op (tree *scev, bool (*cbck) (tree *, void *), void *data)
+{
+  switch (TREE_CODE_LENGTH (TREE_CODE (*scev)))
+    {
+    case 3:
+      for_each_scev_op (&TREE_OPERAND (*scev, 2), cbck, data);
+
+    case 2:
+      for_each_scev_op (&TREE_OPERAND (*scev, 1), cbck, data);
+
+    case 1:
+      for_each_scev_op (&TREE_OPERAND (*scev, 0), cbck, data);
 
     default:
 
     default:
-      {
-       tree res = convert (type, chrec);
-
-       /* Don't propagate overflows.  */
-       TREE_OVERFLOW (res) = 0;
-       if (TREE_CODE_CLASS (TREE_CODE (res)) == 'c')
-         TREE_CONSTANT_OVERFLOW (res) = 0;
-       return res;
-      }
+      cbck (scev, data);
+      break;
     }
 }
 
     }
 }
 
-/* Returns the type of the chrec.  */
+/* Returns true when the operation can be part of a linear
+   expression.  */
 
 
-tree 
-chrec_type (tree chrec)
+static inline bool
+operator_is_linear (tree scev)
 {
 {
-  if (automatically_generated_chrec_p (chrec))
-    return NULL_TREE;
-  
-  return TREE_TYPE (chrec);
+  switch (TREE_CODE (scev))
+    {
+    case INTEGER_CST:
+    case POLYNOMIAL_CHREC:
+    case PLUS_EXPR:
+    case POINTER_PLUS_EXPR:
+    case MULT_EXPR:
+    case MINUS_EXPR:
+    case NEGATE_EXPR:
+    case SSA_NAME:
+    case NON_LVALUE_EXPR:
+    case BIT_NOT_EXPR:
+    CASE_CONVERT:
+      return true;
+
+    default:
+      return false;
+    }
 }
 
 }
 
-extern void initialize_scalar_evolutions_analyzer (void);
+/* Return true when SCEV is a linear expression.  Linear expressions
+   can contain additions, substractions and multiplications.
+   Multiplications are restricted to constant scaling: "cst * x".  */
 
 
-/* Initializer.  */
+bool
+scev_is_linear_expression (tree scev)
+{
+  if (scev == NULL
+      || !operator_is_linear (scev))
+    return false;
 
 
-void
-initialize_scalar_evolutions_analyzer (void)
+  if (TREE_CODE (scev) == MULT_EXPR)
+    return !(tree_contains_chrecs (TREE_OPERAND (scev, 0), NULL)
+            && tree_contains_chrecs (TREE_OPERAND (scev, 1), NULL));
+
+  if (TREE_CODE (scev) == POLYNOMIAL_CHREC
+      && !evolution_function_is_affine_multivariate_p (scev, CHREC_VARIABLE (scev)))
+    return false;
+
+  switch (TREE_CODE_LENGTH (TREE_CODE (scev)))
+    {
+    case 3:
+      return scev_is_linear_expression (TREE_OPERAND (scev, 0))
+       && scev_is_linear_expression (TREE_OPERAND (scev, 1))
+       && scev_is_linear_expression (TREE_OPERAND (scev, 2));
+
+    case 2:
+      return scev_is_linear_expression (TREE_OPERAND (scev, 0))
+       && scev_is_linear_expression (TREE_OPERAND (scev, 1));
+
+    case 1:
+      return scev_is_linear_expression (TREE_OPERAND (scev, 0));
+
+    case 0:
+      return true;
+
+    default:
+      return false;
+    }
+}
+
+/* Determines whether the expression CHREC contains only interger consts
+   in the right parts.  */
+
+bool
+evolution_function_right_is_integer_cst (const_tree chrec)
 {
 {
-  /* The elements below are unique.  */
-  if (chrec_dont_know == NULL_TREE)
+  if (chrec == NULL_TREE)
+    return false;
+
+  switch (TREE_CODE (chrec))
     {
     {
-      chrec_not_analyzed_yet = NULL_TREE;
-      chrec_dont_know = make_node (SCEV_NOT_KNOWN);
-      chrec_known = make_node (SCEV_KNOWN);
-      TREE_TYPE (chrec_dont_know) = NULL_TREE;
-      TREE_TYPE (chrec_known) = NULL_TREE;
+    case INTEGER_CST:
+      return true;
+
+    case POLYNOMIAL_CHREC:
+      if (!evolution_function_right_is_integer_cst (CHREC_RIGHT (chrec)))
+       return false;
+
+      if (TREE_CODE (CHREC_LEFT (chrec)) == POLYNOMIAL_CHREC
+       && !evolution_function_right_is_integer_cst (CHREC_LEFT (chrec)))
+       return false;
+
+      return true;
+
+    default:
+      return false;
     }
 }
     }
 }
+