OSDN Git Service

2006-12-13 Jakub Jelinek <jakub@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-ccp.c
index 9dd63fe..493bdec 100644 (file)
@@ -132,13 +132,12 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 
    We should be able to deduce that the predicate 'a.a != B' is always
    false.  To achieve this, we associate constant values to the SSA
-   names in the V_MAY_DEF and V_MUST_DEF operands for each store.
-   Additionally, since we also glob partial loads/stores with the base
-   symbol, we also keep track of the memory reference where the
-   constant value was stored (in the MEM_REF field of PROP_VALUE_T).
-   For instance,
+   names in the VDEF operands for each store.  Additionally,
+   since we also glob partial loads/stores with the base symbol, we
+   also keep track of the memory reference where the constant value
+   was stored (in the MEM_REF field of PROP_VALUE_T).  For instance,
 
-        # a_5 = V_MAY_DEF <a_4>
+        # a_5 = VDEF <a_4>
         a.a = 2;
 
         # VUSE <a_5>
@@ -222,9 +221,9 @@ typedef enum
 /* Array of propagated constant values.  After propagation,
    CONST_VAL[I].VALUE holds the constant value for SSA_NAME(I).  If
    the constant is held in an SSA name representing a memory store
-   (i.e., a V_MAY_DEF or V_MUST_DEF), CONST_VAL[I].MEM_REF will
-   contain the actual memory reference used to store (i.e., the LHS of
-   the assignment doing the store).  */
+   (i.e., a VDEF), CONST_VAL[I].MEM_REF will contain the actual
+   memory reference used to store (i.e., the LHS of the assignment
+   doing the store).  */
 static prop_value_t *const_val;
 
 /* True if we are also propagating constants in stores and loads.  */
@@ -293,6 +292,24 @@ ccp_decl_initial_min_invariant (tree t)
   return true;
 }
 
+/* If SYM is a constant variable with known value, return the value.
+   NULL_TREE is returned otherwise.  */
+
+static tree
+get_symbol_constant_value (tree sym)
+{
+  if (TREE_STATIC (sym)
+      && TREE_READONLY (sym)
+      && !MTAG_P (sym))
+    {
+      tree val = DECL_INITIAL (sym);
+      if (val
+         && ccp_decl_initial_min_invariant (val))
+       return val;
+    }
+
+  return NULL_TREE;
+}
 
 /* Compute a default value for variable VAR and store it in the
    CONST_VAL array.  The following rules are used to get default
@@ -320,6 +337,7 @@ get_default_value (tree var)
 {
   tree sym = SSA_NAME_VAR (var);
   prop_value_t val = { UNINITIALIZED, NULL_TREE, NULL_TREE };
+  tree cst_val;
   
   if (!do_store_ccp && !is_gimple_reg (var))
     {
@@ -333,16 +351,12 @@ get_default_value (tree var)
       val.lattice_val = CONSTANT;
       val.value = SSA_NAME_VALUE (var);
     }
-  else if (TREE_STATIC (sym)
-          && TREE_READONLY (sym)
-          && !MTAG_P (sym)
-          && DECL_INITIAL (sym)
-          && ccp_decl_initial_min_invariant (DECL_INITIAL (sym)))
+  else if ((cst_val = get_symbol_constant_value (sym)) != NULL_TREE)
     {
       /* Globals and static variables declared 'const' take their
         initial value.  */
       val.lattice_val = CONSTANT;
-      val.value = DECL_INITIAL (sym);
+      val.value = cst_val;
       val.mem_ref = sym;
     }
   else
@@ -360,7 +374,7 @@ get_default_value (tree var)
          else
            val.lattice_val = VARYING;
        }
-      else if (TREE_CODE (stmt) == MODIFY_EXPR
+      else if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
               || TREE_CODE (stmt) == PHI_NODE)
        {
          /* Any other variable defined by an assignment or a PHI node
@@ -403,6 +417,54 @@ set_value_varying (tree var)
   val->mem_ref = NULL_TREE;
 }
 
+/* For float types, modify the value of VAL to make ccp work correctly
+   for non-standard values (-0, NaN):
+
+   If HONOR_SIGNED_ZEROS is false, and VAL = -0, we canonicalize it to 0.
+   If HONOR_NANS is false, and VAL is NaN, we canonicalize it to UNDEFINED.
+     This is to fix the following problem (see PR 29921): Suppose we have
+
+     x = 0.0 * y
+
+     and we set value of y to NaN.  This causes value of x to be set to NaN.
+     When we later determine that y is in fact VARYING, fold uses the fact
+     that HONOR_NANS is false, and we try to change the value of x to 0,
+     causing an ICE.  With HONOR_NANS being false, the real appearance of
+     NaN would cause undefined behavior, though, so claiming that y (and x)
+     are UNDEFINED initially is correct.  */
+
+static void
+canonicalize_float_value (prop_value_t *val)
+{
+  enum machine_mode mode;
+  tree type;
+  REAL_VALUE_TYPE d;
+
+  if (val->lattice_val != CONSTANT
+      || TREE_CODE (val->value) != REAL_CST)
+    return;
+
+  d = TREE_REAL_CST (val->value);
+  type = TREE_TYPE (val->value);
+  mode = TYPE_MODE (type);
+
+  if (!HONOR_SIGNED_ZEROS (mode)
+      && REAL_VALUE_MINUS_ZERO (d))
+    {
+      val->value = build_real (type, dconst0);
+      return;
+    }
+
+  if (!HONOR_NANS (mode)
+      && REAL_VALUE_ISNAN (d))
+    {
+      val->lattice_val = UNDEFINED;
+      val->value = NULL;
+      val->mem_ref = NULL;
+      return;
+    }
+}
+
 /* Set the value for variable VAR to NEW_VAL.  Return true if the new
    value is different from VAR's previous value.  */
 
@@ -411,13 +473,16 @@ set_lattice_value (tree var, prop_value_t new_val)
 {
   prop_value_t *old_val = get_value (var);
 
+  canonicalize_float_value (&new_val);
+
   /* Lattice transitions must always be monotonically increasing in
      value.  If *OLD_VAL and NEW_VAL are the same, return false to
      inform the caller that this was a non-transition.  */
 
-  gcc_assert (old_val->lattice_val <= new_val.lattice_val
+  gcc_assert (old_val->lattice_val < new_val.lattice_val
               || (old_val->lattice_val == new_val.lattice_val
-                 && old_val->value == new_val.value
+                 && ((!old_val->value && !new_val.value)
+                     || operand_equal_p (old_val->value, new_val.value, 0))
                  && old_val->mem_ref == new_val.mem_ref));
 
   if (old_val->lattice_val != new_val.lattice_val)
@@ -477,7 +542,7 @@ likely_value (tree stmt)
 
   /* Anything other than assignments and conditional jumps are not
      interesting for CCP.  */
-  if (TREE_CODE (stmt) != MODIFY_EXPR
+  if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT
       && !(TREE_CODE (stmt) == RETURN_EXPR && get_rhs (stmt) != NULL_TREE)
       && TREE_CODE (stmt) != COND_EXPR
       && TREE_CODE (stmt) != SWITCH_EXPR)
@@ -535,7 +600,7 @@ surely_varying_stmt_p (tree stmt)
 
   /* Anything other than assignments and conditional jumps are not
      interesting for CCP.  */
-  if (TREE_CODE (stmt) != MODIFY_EXPR
+  if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT
       && !(TREE_CODE (stmt) == RETURN_EXPR && get_rhs (stmt) != NULL_TREE)
       && TREE_CODE (stmt) != COND_EXPR
       && TREE_CODE (stmt) != SWITCH_EXPR)
@@ -1118,8 +1183,8 @@ visit_assignment (tree stmt, tree *output_p)
   tree lhs, rhs;
   enum ssa_prop_result retval;
 
-  lhs = TREE_OPERAND (stmt, 0);
-  rhs = TREE_OPERAND (stmt, 1);
+  lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+  rhs = GIMPLE_STMT_OPERAND (stmt, 1);
 
   if (TREE_CODE (rhs) == SSA_NAME)
     {
@@ -1153,7 +1218,7 @@ visit_assignment (tree stmt, tree *output_p)
      the constant value into the type of the destination variable.  This
      should not be necessary if GCC represented bitfields properly.  */
   {
-    tree orig_lhs = TREE_OPERAND (stmt, 0);
+    tree orig_lhs = GIMPLE_STMT_OPERAND (stmt, 0);
 
     if (TREE_CODE (orig_lhs) == VIEW_CONVERT_EXPR
        && val.lattice_val == CONSTANT)
@@ -1208,9 +1273,9 @@ visit_assignment (tree stmt, tree *output_p)
     }
   else if (do_store_ccp && stmt_makes_single_store (stmt))
     {
-      /* Otherwise, set the names in V_MAY_DEF/V_MUST_DEF operands
-        to the new constant value and mark the LHS as the memory
-        reference associated with VAL.  */
+      /* Otherwise, set the names in VDEF operands to the new
+        constant value and mark the LHS as the memory reference
+        associated with VAL.  */
       ssa_op_iter i;
       tree vdef;
       bool changed;
@@ -1222,7 +1287,15 @@ visit_assignment (tree stmt, tree *output_p)
       /* Set the value of every VDEF to VAL.  */
       changed = false;
       FOR_EACH_SSA_TREE_OPERAND (vdef, stmt, i, SSA_OP_VIRTUAL_DEFS)
-       changed |= set_lattice_value (vdef, val);
+       {
+         /* See PR 29801.  We may have VDEFs for read-only variables
+            (see the handling of unmodifiable variables in
+            add_virtual_operand); do not attempt to change their value.  */
+         if (get_symbol_constant_value (SSA_NAME_VAR (vdef)) != NULL_TREE)
+           continue;
+
+         changed |= set_lattice_value (vdef, val);
+       }
       
       /* Note that for propagation purposes, we are only interested in
         visiting statements that load the exact same memory reference
@@ -1290,7 +1363,7 @@ ccp_visit_stmt (tree stmt, edge *taken_edge_p, tree *output_p)
       fprintf (dump_file, "\n");
     }
 
-  if (TREE_CODE (stmt) == MODIFY_EXPR)
+  if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
     {
       /* If the statement is an assignment that produces a single
         output value, evaluate its RHS to see if the lattice value of
@@ -1360,11 +1433,15 @@ struct tree_opt_pass pass_ccp =
   TV_TREE_CCP,                         /* tv_id */
   PROP_cfg | PROP_ssa | PROP_alias,    /* properties_required */
   0,                                   /* properties_provided */
-  PROP_smt_usage,                      /* properties_destroyed */
+  0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_cleanup_cfg | TODO_dump_func | TODO_update_ssa
-    | TODO_ggc_collect | TODO_verify_ssa
-    | TODO_verify_stmts | TODO_update_smt_usage, /* todo_flags_finish */
+  TODO_cleanup_cfg
+    | TODO_dump_func
+    | TODO_update_ssa
+    | TODO_ggc_collect
+    | TODO_verify_ssa
+    | TODO_verify_stmts
+    | TODO_update_smt_usage,           /* todo_flags_finish */
   0                                    /* letter */
 };
 
@@ -1398,12 +1475,15 @@ struct tree_opt_pass pass_store_ccp =
   TV_TREE_STORE_CCP,                   /* tv_id */
   PROP_cfg | PROP_ssa | PROP_alias,    /* properties_required */
   0,                                   /* properties_provided */
-  PROP_smt_usage,                      /* properties_destroyed */
+  0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_update_ssa
-    | TODO_ggc_collect | TODO_verify_ssa
+  TODO_dump_func
+    | TODO_update_ssa
+    | TODO_ggc_collect
+    | TODO_verify_ssa
     | TODO_cleanup_cfg
-    | TODO_verify_stmts | TODO_update_smt_usage, /* todo_flags_finish */
+    | TODO_verify_stmts
+    | TODO_update_smt_usage,           /* todo_flags_finish */
   0                                    /* letter */
 };
 
@@ -2071,14 +2151,14 @@ get_maxval_strlen (tree arg, tree *length, bitmap visited, int type)
 
   switch (TREE_CODE (def_stmt))
     {
-      case MODIFY_EXPR:
+      case GIMPLE_MODIFY_STMT:
        {
          tree rhs;
 
          /* The RHS of the statement defining VAR must either have a
             constant length or come from another SSA_NAME with a constant
             length.  */
-         rhs = TREE_OPERAND (def_stmt, 1);
+         rhs = GIMPLE_STMT_OPERAND (def_stmt, 1);
          STRIP_NOPS (rhs);
          return get_maxval_strlen (rhs, length, visited, type);
        }
@@ -2130,7 +2210,7 @@ ccp_fold_builtin (tree stmt, tree fn)
   bitmap visited;
   bool ignore;
 
-  ignore = TREE_CODE (stmt) != MODIFY_EXPR;
+  ignore = TREE_CODE (stmt) != GIMPLE_MODIFY_STMT;
 
   /* First try the generic builtin folder.  If that succeeds, return the
      result directly.  */
@@ -2234,13 +2314,13 @@ ccp_fold_builtin (tree stmt, tree fn)
 
     case BUILT_IN_FPUTS:
       result = fold_builtin_fputs (arglist,
-                                  TREE_CODE (stmt) != MODIFY_EXPR, 0,
+                                  TREE_CODE (stmt) != GIMPLE_MODIFY_STMT, 0,
                                   val[0]);
       break;
 
     case BUILT_IN_FPUTS_UNLOCKED:
       result = fold_builtin_fputs (arglist,
-                                  TREE_CODE (stmt) != MODIFY_EXPR, 1,
+                                  TREE_CODE (stmt) != GIMPLE_MODIFY_STMT, 1,
                                   val[0]);
       break;
 
@@ -2438,7 +2518,7 @@ convert_to_gimple_builtin (block_stmt_iterator *si_p, tree expr, bool ignore)
       tree new_stmt = tsi_stmt (ti);
       find_new_referenced_vars (tsi_stmt_ptr (ti));
       bsi_insert_before (si_p, new_stmt, BSI_NEW_STMT);
-      mark_new_vars_to_rename (bsi_stmt (*si_p));
+      mark_symbols_for_renaming (new_stmt);
       bsi_next (si_p);
     }
 
@@ -2500,19 +2580,22 @@ execute_fold_all_builtins (void)
              print_generic_stmt (dump_file, *stmtp, dump_flags);
            }
 
+         push_stmt_changes (stmtp);
+
          if (!set_rhs (stmtp, result))
            {
              result = convert_to_gimple_builtin (&i, result,
                                                  TREE_CODE (old_stmt)
-                                                 != MODIFY_EXPR);
+                                                 != GIMPLE_MODIFY_STMT);
              if (result)
                {
                  bool ok = set_rhs (stmtp, result);
-                 
                  gcc_assert (ok);
                }
            }
-         mark_new_vars_to_rename (*stmtp);
+
+         pop_stmt_changes (stmtp);
+
          if (maybe_clean_or_replace_eh_stmt (old_stmt, *stmtp)
              && tree_purge_dead_eh_edges (bb))
            cfg_changed = true;