OSDN Git Service

* gcc.target/powerpc/ppc-spe64-1.c: Add dg-error handler.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-ccp.c
index 9fe0753..d0fcf39 100644 (file)
@@ -501,7 +501,7 @@ likely_value (gimple stmt)
   tree use;
   ssa_op_iter iter;
 
-  enum tree_code code = gimple_code (stmt);
+  enum gimple_code code = gimple_code (stmt);
 
   /* This function appears to be called only for assignments, calls,
      conditionals, and switches, due to the logic in visit_stmt.  */
@@ -851,6 +851,35 @@ ccp_visit_phi_node (gimple phi)
     return SSA_PROP_NOT_INTERESTING;
 }
 
+/* Return true if we may propagate the address expression ADDR into the 
+   dereference DEREF and cancel them.  */
+
+bool
+may_propagate_address_into_dereference (tree addr, tree deref)
+{
+  gcc_assert (INDIRECT_REF_P (deref)
+             && TREE_CODE (addr) == ADDR_EXPR);
+
+  /* Don't propagate if ADDR's operand has incomplete type.  */
+  if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_OPERAND (addr, 0))))
+    return false;
+
+  /* If the address is invariant then we do not need to preserve restrict
+     qualifications.  But we do need to preserve volatile qualifiers until
+     we can annotate the folded dereference itself properly.  */
+  if (is_gimple_min_invariant (addr)
+      && (!TREE_THIS_VOLATILE (deref)
+         || TYPE_VOLATILE (TREE_TYPE (addr))))
+    return useless_type_conversion_p (TREE_TYPE (deref),
+                                     TREE_TYPE (TREE_OPERAND (addr, 0)));
+
+  /* Else both the address substitution and the folding must result in
+     a valid useless type conversion sequence.  */
+  return (useless_type_conversion_p (TREE_TYPE (TREE_OPERAND (deref, 0)),
+                                    TREE_TYPE (addr))
+         && useless_type_conversion_p (TREE_TYPE (deref),
+                                       TREE_TYPE (TREE_OPERAND (addr, 0))));
+}
 
 /* CCP specific front-end to the non-destructive constant folding
    routines.
@@ -897,12 +926,8 @@ ccp_fold (gimple stmt)
                      prop_value_t *val = get_value (TREE_OPERAND (*base, 0));
                      if (val->lattice_val == CONSTANT
                          && TREE_CODE (val->value) == ADDR_EXPR
-                         && useless_type_conversion_p
-                         (TREE_TYPE (TREE_OPERAND (*base, 0)),
-                          TREE_TYPE (val->value))
-                         && useless_type_conversion_p
-                         (TREE_TYPE (*base),
-                          TREE_TYPE (TREE_OPERAND (val->value, 0))))
+                         && may_propagate_address_into_dereference
+                              (val->value, *base))
                        {
                          /* We need to return a new tree, not modify the IL
                             or share parts of it.  So play some tricks to
@@ -1047,6 +1072,7 @@ ccp_fold (gimple stmt)
              fn = val->value;
          }
        if (TREE_CODE (fn) == ADDR_EXPR
+           && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
            && DECL_BUILT_IN (TREE_OPERAND (fn, 0)))
          {
            tree *args = XALLOCAVEC (tree, gimple_call_num_args (stmt));
@@ -1308,7 +1334,7 @@ evaluate_stmt (gimple stmt)
      bother folding the statement.  */
   else if (likelyvalue == VARYING)
     {
-      enum tree_code code = gimple_code (stmt);
+      enum gimple_code code = gimple_code (stmt);
       if (code == GIMPLE_ASSIGN)
         {
           enum tree_code subcode = gimple_assign_rhs_code (stmt);
@@ -2169,6 +2195,9 @@ fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data)
 
       t = maybe_fold_stmt_indirect (expr, TREE_OPERAND (expr, 0),
                                    integer_zero_node);
+      /* Avoid folding *"abc" = 5 into 'a' = 5.  */
+      if (wi->is_lhs && t && TREE_CODE (t) == INTEGER_CST)
+       t = NULL_TREE;
       if (!t
          && TREE_CODE (TREE_OPERAND (expr, 0)) == ADDR_EXPR)
        /* If we had a good reason for propagating the address here,
@@ -2197,8 +2226,10 @@ fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data)
         Otherwise we'd be wasting time.  */
     case ARRAY_REF:
       /* If we are not processing expressions found within an
-        ADDR_EXPR, then we can fold constant array references.  */
-      if (!*inside_addr_expr_p)
+        ADDR_EXPR, then we can fold constant array references.
+        Don't fold on LHS either, to avoid folding "abc"[0] = 5
+        into 'a' = 5.  */
+      if (!*inside_addr_expr_p && !wi->is_lhs)
        t = fold_read_from_constant_string (expr);
       else
        t = NULL;
@@ -2429,7 +2460,7 @@ ccp_fold_builtin (gimple stmt)
 {
   tree result, val[3];
   tree callee, a;
-  int arg_mask, i, type;
+  int arg_idx, type;
   bitmap visited;
   bool ignore;
   int nargs;
@@ -2465,12 +2496,12 @@ ccp_fold_builtin (gimple stmt)
     case BUILT_IN_STRLEN:
     case BUILT_IN_FPUTS:
     case BUILT_IN_FPUTS_UNLOCKED:
-      arg_mask = 1;
+      arg_idx = 0;
       type = 0;
       break;
     case BUILT_IN_STRCPY:
     case BUILT_IN_STRNCPY:
-      arg_mask = 2;
+      arg_idx = 1;
       type = 0;
       break;
     case BUILT_IN_MEMCPY_CHK:
@@ -2478,37 +2509,34 @@ ccp_fold_builtin (gimple stmt)
     case BUILT_IN_MEMMOVE_CHK:
     case BUILT_IN_MEMSET_CHK:
     case BUILT_IN_STRNCPY_CHK:
-      arg_mask = 4;
+      arg_idx = 2;
       type = 2;
       break;
     case BUILT_IN_STRCPY_CHK:
     case BUILT_IN_STPCPY_CHK:
-      arg_mask = 2;
+      arg_idx = 1;
       type = 1;
       break;
     case BUILT_IN_SNPRINTF_CHK:
     case BUILT_IN_VSNPRINTF_CHK:
-      arg_mask = 2;
+      arg_idx = 1;
       type = 2;
       break;
     default:
       return NULL_TREE;
     }
 
+  if (arg_idx >= nargs)
+    return NULL_TREE;
+
   /* Try to use the dataflow information gathered by the CCP process.  */
   visited = BITMAP_ALLOC (NULL);
+  bitmap_clear (visited);
 
   memset (val, 0, sizeof (val));
-  for (i = 0; i < nargs; i++)
-    {
-      if ((arg_mask >> i) & 1)
-        {
-          a = gimple_call_arg (stmt, i);
-          bitmap_clear (visited);
-          if (!get_maxval_strlen (a, &val[i], visited, type))
-            val[i] = NULL_TREE;
-        }
-    }
+  a = gimple_call_arg (stmt, arg_idx);
+  if (!get_maxval_strlen (a, &val[arg_idx], visited, type))
+    val[arg_idx] = NULL_TREE;
 
   BITMAP_FREE (visited);
 
@@ -2516,7 +2544,7 @@ ccp_fold_builtin (gimple stmt)
   switch (DECL_FUNCTION_CODE (callee))
     {
     case BUILT_IN_STRLEN:
-      if (val[0])
+      if (val[0] && nargs == 1)
        {
          tree new_val =
               fold_convert (TREE_TYPE (gimple_call_lhs (stmt)), val[0]);
@@ -2548,22 +2576,24 @@ ccp_fold_builtin (gimple stmt)
       break;
 
     case BUILT_IN_FPUTS:
-      result = fold_builtin_fputs (gimple_call_arg (stmt, 0),
-                                   gimple_call_arg (stmt, 1),
-                                  ignore, false, val[0]);
+      if (nargs == 2)
+       result = fold_builtin_fputs (gimple_call_arg (stmt, 0),
+                                    gimple_call_arg (stmt, 1),
+                                    ignore, false, val[0]);
       break;
 
     case BUILT_IN_FPUTS_UNLOCKED:
-      result = fold_builtin_fputs (gimple_call_arg (stmt, 0),
-                                  gimple_call_arg (stmt, 1),
-                                   ignore, true, val[0]);
+      if (nargs == 2)
+       result = fold_builtin_fputs (gimple_call_arg (stmt, 0),
+                                    gimple_call_arg (stmt, 1),
+                                    ignore, true, val[0]);
       break;
 
     case BUILT_IN_MEMCPY_CHK:
     case BUILT_IN_MEMPCPY_CHK:
     case BUILT_IN_MEMMOVE_CHK:
     case BUILT_IN_MEMSET_CHK:
-      if (val[2] && is_gimple_val (val[2]))
+      if (val[2] && is_gimple_val (val[2]) && nargs == 4)
        result = fold_builtin_memory_chk (callee,
                                           gimple_call_arg (stmt, 0),
                                           gimple_call_arg (stmt, 1),
@@ -2575,7 +2605,7 @@ ccp_fold_builtin (gimple stmt)
 
     case BUILT_IN_STRCPY_CHK:
     case BUILT_IN_STPCPY_CHK:
-      if (val[1] && is_gimple_val (val[1]))
+      if (val[1] && is_gimple_val (val[1]) && nargs == 3)
        result = fold_builtin_stxcpy_chk (callee,
                                           gimple_call_arg (stmt, 0),
                                           gimple_call_arg (stmt, 1),
@@ -2585,7 +2615,7 @@ ccp_fold_builtin (gimple stmt)
       break;
 
     case BUILT_IN_STRNCPY_CHK:
-      if (val[2] && is_gimple_val (val[2]))
+      if (val[2] && is_gimple_val (val[2]) && nargs == 4)
        result = fold_builtin_strncpy_chk (gimple_call_arg (stmt, 0),
                                            gimple_call_arg (stmt, 1),
                                            gimple_call_arg (stmt, 2),
@@ -2694,10 +2724,19 @@ fold_gimple_assign (gimple_stmt_iterator *si)
     case GIMPLE_BINARY_RHS:
       /* Try to fold pointer addition.  */
       if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
-        result = maybe_fold_stmt_addition (
-                   TREE_TYPE (gimple_assign_lhs (stmt)),
-                   gimple_assign_rhs1 (stmt),
-                   gimple_assign_rhs2 (stmt));
+       {
+         tree type = TREE_TYPE (gimple_assign_rhs1 (stmt));
+         if (TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE)
+           {
+             type = build_pointer_type (TREE_TYPE (TREE_TYPE (type)));
+             if (!useless_type_conversion_p
+                   (TREE_TYPE (gimple_assign_lhs (stmt)), type))
+               type = TREE_TYPE (gimple_assign_rhs1 (stmt));
+           }
+         result = maybe_fold_stmt_addition (type,
+                                            gimple_assign_rhs1 (stmt),
+                                            gimple_assign_rhs2 (stmt));
+       }
 
       if (!result)
         result = fold_binary (subcode,
@@ -2710,6 +2749,17 @@ fold_gimple_assign (gimple_stmt_iterator *si)
           STRIP_USELESS_TYPE_CONVERSION (result);
           if (valid_gimple_rhs_p (result))
            return result;
+
+         /* Fold might have produced non-GIMPLE, so if we trust it blindly
+            we lose canonicalization opportunities.  Do not go again
+            through fold here though, or the same non-GIMPLE will be
+            produced.  */
+          if (commutative_tree_code (subcode)
+              && tree_swap_operands_p (gimple_assign_rhs1 (stmt),
+                                       gimple_assign_rhs2 (stmt), false))
+            return build2 (subcode, TREE_TYPE (gimple_assign_lhs (stmt)),
+                           gimple_assign_rhs2 (stmt),
+                           gimple_assign_rhs1 (stmt));
         }
       break;