OSDN Git Service

libcpp/
[pf3gnuchains/gcc-fork.git] / gcc / tree-chrec.c
index 4d62b51..0bf1d38 100644 (file)
@@ -30,6 +30,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "tm.h"
 #include "ggc.h"
 #include "tree.h"
+#include "real.h"
 #include "diagnostic.h"
 #include "varray.h"
 #include "cfgloop.h"
@@ -37,6 +38,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "tree-chrec.h"
 #include "tree-pass.h"
 #include "params.h"
+#include "tree-scalar-evolution.h"
 
 \f
 
@@ -119,7 +121,9 @@ 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), 
-                               build_int_cst_type (type, -1)));
+                               SCALAR_FLOAT_TYPE_P (type)
+                               ? build_real (type, dconstm1)
+                               : build_int_cst_type (type, -1)));
     }
   
   if (CHREC_VARIABLE (poly0) > CHREC_VARIABLE (poly1))
@@ -167,6 +171,9 @@ chrec_fold_multiply_poly_poly (tree type,
                               tree poly0, 
                               tree poly1)
 {
+  tree t0, t1, t2;
+  int var;
+
   gcc_assert (poly0);
   gcc_assert (poly1);
   gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC);
@@ -191,28 +198,27 @@ chrec_fold_multiply_poly_poly (tree type,
   
   /* 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 + b*d".  */
+  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)));
+  t1 = chrec_fold_plus (type, t1, chrec_fold_multiply (type,
+                                                      CHREC_RIGHT (poly0),
+                                                      CHREC_RIGHT (poly1)));
+  /* "2*b*d".  */
+  t2 = chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1));
+  t2 = chrec_fold_multiply (type, SCALAR_FLOAT_TYPE_P (type)
+                           ? build_real (type, dconst2)
+                           : build_int_cst_type (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
@@ -284,8 +290,10 @@ chrec_fold_plus_1 (enum tree_code code,
            return build_polynomial_chrec 
              (CHREC_VARIABLE (op1), 
               chrec_fold_minus (type, op0, CHREC_LEFT (op1)),
-              chrec_fold_multiply (type, CHREC_RIGHT (op1),
-                                   build_int_cst_type (type, -1)));
+              chrec_fold_multiply (type, CHREC_RIGHT (op1), 
+                                   SCALAR_FLOAT_TYPE_P (type)
+                                   ? build_real (type, dconstm1)
+                                   : build_int_cst_type (type, -1)));
 
        default:
          {
@@ -532,6 +540,9 @@ chrec_apply (unsigned var,
   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".  */
@@ -924,9 +935,16 @@ evolution_function_is_invariant_rec_p (tree chrec, int loopnum)
                                   chrec))
     return true;
 
-  if (TREE_CODE (chrec) == POLYNOMIAL_CHREC
-      && CHREC_VARIABLE (chrec) == (unsigned) loopnum)
-    return false;
+  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_CODE_LENGTH (TREE_CODE (chrec)))
     {
@@ -1110,11 +1128,44 @@ chrec_convert (tree type, tree chrec, tree at_stmt)
 
   if (evolution_function_is_affine_p (chrec))
     {
-      tree step = convert_step (current_loops->parray[CHREC_VARIABLE (chrec)],
-                               type, CHREC_LEFT (chrec), CHREC_RIGHT (chrec),
-                               at_stmt);
+      tree base, step;
+      bool dummy;
+      struct loop *loop = current_loops->parray[CHREC_VARIABLE (chrec)];
+
+      base = instantiate_parameters (loop, CHREC_LEFT (chrec));
+      step = instantiate_parameters (loop, CHREC_RIGHT (chrec));
+
+      /* Avoid conversion of (signed char) {(uchar)1, +, (uchar)1}_x
+        when it is not possible to prove that the scev does not wrap.
+        See PR22236, where a sequence 1, 2, ..., 255 has to be
+        converted to signed char, but this would wrap: 
+        1, 2, ..., 127, -128, ...  The result should not be
+        {(schar)1, +, (schar)1}_x, but instead, we should keep the
+        conversion: (schar) {(uchar)1, +, (uchar)1}_x.  */
+      if (scev_probably_wraps_p (type, base, step, at_stmt, loop,
+                                &dummy, &dummy))
+       goto failed_to_convert;
+
+      step = convert_step (loop, type, base, step, at_stmt);
       if (!step)
-       return fold_convert (type, chrec);
+       {
+       failed_to_convert:;
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             fprintf (dump_file, "(failed conversion:");
+             fprintf (dump_file, "\n  type: ");
+             print_generic_expr (dump_file, type, 0);
+             fprintf (dump_file, "\n  base: ");
+             print_generic_expr (dump_file, base, 0);
+             fprintf (dump_file, "\n  step: ");
+             print_generic_expr (dump_file, step, 0);
+             fprintf (dump_file, "\n  estimated_nb_iterations: ");
+             print_generic_expr (dump_file, loop->estimated_nb_iterations, 0);
+             fprintf (dump_file, "\n)\n");
+           }
+
+         return fold_convert (type, chrec);
+       }
 
       return build_polynomial_chrec (CHREC_VARIABLE (chrec),
                                     chrec_convert (type, CHREC_LEFT (chrec),
@@ -1148,6 +1199,35 @@ chrec_convert (tree type, tree chrec, tree at_stmt)
   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;
+
+  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;
+
+  left = CHREC_LEFT (chrec);
+  right = CHREC_RIGHT (chrec);
+  lc = chrec_convert_aggressive (type, left);
+  if (!lc)
+    lc = chrec_convert (type, left, NULL_TREE);
+  rc = chrec_convert_aggressive (type, right);
+  if (!rc)
+    rc = chrec_convert (type, right, NULL_TREE);
+
+  return build_polynomial_chrec (CHREC_VARIABLE (chrec), lc, rc);
+}
+
 /* Returns the type of the chrec.  */
 
 tree