OSDN Git Service

PR target/39558
[pf3gnuchains/gcc-fork.git] / gcc / tree-affine.c
index 54f36b9..b67064b 100644 (file)
@@ -1,5 +1,5 @@
 /* Operations with affine combinations of trees.
-   Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
    
 This file is part of GCC.
    
@@ -30,7 +30,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dump.h"
 #include "pointer-set.h"
 #include "tree-affine.h"
-#include "tree-gimple.h"
+#include "gimple.h"
+#include "flags.h"
 
 /* Extends CST as appropriate for the affine combinations COMB.  */
 
@@ -566,11 +567,13 @@ struct name_expansion
    results.  */
 
 void
-aff_combination_expand (aff_tree *comb, struct pointer_map_t **cache)
+aff_combination_expand (aff_tree *comb ATTRIBUTE_UNUSED,
+                       struct pointer_map_t **cache ATTRIBUTE_UNUSED)
 {
   unsigned i;
   aff_tree to_add, current, curre;
-  tree e, def, rhs;
+  tree e, rhs;
+  gimple def;
   double_int scale;
   void **slot;
   struct name_expansion *exp;
@@ -578,35 +581,67 @@ aff_combination_expand (aff_tree *comb, struct pointer_map_t **cache)
   aff_combination_zero (&to_add, comb->type);
   for (i = 0; i < comb->n; i++)
     {
+      tree type, name;
+      enum tree_code code;
+
       e = comb->elts[i].val;
-      if (TREE_CODE (e) != SSA_NAME)
+      type = TREE_TYPE (e);
+      name = e;
+      /* Look through some conversions.  */
+      if (TREE_CODE (e) == NOP_EXPR
+          && (TYPE_PRECISION (type)
+             >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (e, 0)))))
+       name = TREE_OPERAND (e, 0);
+      if (TREE_CODE (name) != SSA_NAME)
        continue;
-      def = SSA_NAME_DEF_STMT (e);
-      if (TREE_CODE (def) != GIMPLE_MODIFY_STMT
-         || GIMPLE_STMT_OPERAND (def, 0) != e)
+      def = SSA_NAME_DEF_STMT (name);
+      if (!is_gimple_assign (def) || gimple_assign_lhs (def) != name)
        continue;
 
-      rhs = GIMPLE_STMT_OPERAND (def, 1);
-      if (TREE_CODE (rhs) != SSA_NAME
-         && !EXPR_P (rhs)
-         && !is_gimple_min_invariant (rhs))
+      code = gimple_assign_rhs_code (def);
+      if (code != SSA_NAME
+         && !IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code))
+         && (get_gimple_rhs_class (code) != GIMPLE_SINGLE_RHS
+             || !is_gimple_min_invariant (gimple_assign_rhs1 (def))))
        continue;
 
       /* We do not know whether the reference retains its value at the
         place where the expansion is used.  */
-      if (REFERENCE_CLASS_P (rhs))
+      if (TREE_CODE_CLASS (code) == tcc_reference)
        continue;
 
       if (!*cache)
        *cache = pointer_map_create ();
       slot = pointer_map_insert (*cache, e);
-      exp = *slot;
+      exp = (struct name_expansion *) *slot;
 
       if (!exp)
        {
          exp = XNEW (struct name_expansion);
          exp->in_progress = 1;
          *slot = exp;
+         /* In principle this is a generally valid folding, but
+            it is not unconditionally an optimization, so do it
+            here and not in fold_unary.  */
+         /* Convert (T1)(X *+- CST) into (T1)X *+- (T1)CST if T1 is wider
+            than the type of X and overflow for the type of X is
+            undefined.  */
+         if (e != name
+             && INTEGRAL_TYPE_P (type)
+             && INTEGRAL_TYPE_P (TREE_TYPE (name))
+             && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (name))
+             && TYPE_PRECISION (type) > TYPE_PRECISION (TREE_TYPE (name))
+             && (code == PLUS_EXPR || code == MINUS_EXPR || code == MULT_EXPR)
+             && TREE_CODE (gimple_assign_rhs2 (def)) == INTEGER_CST)
+           rhs = fold_build2 (code, type,
+                              fold_convert (type, gimple_assign_rhs1 (def)),
+                              fold_convert (type, gimple_assign_rhs2 (def)));
+         else
+           {
+             rhs = gimple_assign_rhs_to_tree (def);
+             if (e != name)
+               rhs = fold_convert (type, rhs);
+           }
          tree_to_aff_combination_expand (rhs, comb->type, &current, cache);
          exp->expansion = current;
          exp->in_progress = 0;
@@ -657,7 +692,7 @@ static bool
 free_name_expansion (const void *key ATTRIBUTE_UNUSED, void **value,
                     void *data ATTRIBUTE_UNUSED)
 {
-  struct name_expansion *exp = *value;
+  struct name_expansion *const exp = (struct name_expansion *) *value;
 
   free (exp);
   return true;