tree-ssa-ccp.c (latticevalue): Add UNKNOWN_VAL.
authorBrian Booth <bbooth@gcc.gnu.org>
Thu, 22 Jul 2004 18:33:20 +0000 (18:33 +0000)
committerBrian Booth <bbooth@gcc.gnu.org>
Thu, 22 Jul 2004 18:33:20 +0000 (18:33 +0000)
* tree-ssa-ccp.c (latticevalue): Add UNKNOWN_VAL.
(substitute_and_fold): Propigate into VUSE operands when possible.
(visit_phi_node): Handle UNKNOWN_VAL latticevalue.
(cp_lattice_meet): Handle merging of latticevalues when
UNKNOWN_VAL is present.
(visit_stmt): Visit assignments with V_MUST_DEFs.
(visit_assignment): Gather ccp information for V_MUST_DEF operands.
(ccp_fold): Deal with RHS' that are constant and virtual.
(evaluate_stmt): Handle UNKNOWN_VAL likely values.
(dump_lattice_value): Dump UNKNOWN_VAL latticevalues.
(initialize): Mark statements with V_MUST_DEFs as VARYING only if the
V_MUST_DEF operand is VARYING. Fix comment and include VOPS when
computing immediate uses.
(set_lattice_value): Disallow a UNKNOWN_VAL->UNDEFINED state
transition.
(replace_vuse_in): New function.
(likely_value): Add check of vuse operands.
(get_default_value): Set the default value of virtually defined
variables to UKNOWN_VAL instead of VARYING.

testsuite:

* gcc.dg/tree-ssa/20040721-1.c: New test.

From-SVN: r85055

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/20040721-1.c [new file with mode: 0644]
gcc/tree-ssa-ccp.c

index 53fdc1d9da8eedbc5ee6027af9116e71bf2709bd..3672398b9cc4d7453b8bc60c25b6b05ed5f1167b 100644 (file)
@@ -1,3 +1,25 @@
+2004-07-22  Brian Booth  <bbooth@redhat.com>
+
+       * tree-ssa-ccp.c (latticevalue): Add UNKNOWN_VAL.
+       (substitute_and_fold): Propigate into VUSE operands when possible.
+       (visit_phi_node): Handle UNKNOWN_VAL latticevalue.
+       (cp_lattice_meet): Handle merging of latticevalues when 
+       UNKNOWN_VAL is present.
+       (visit_stmt): Visit assignments with V_MUST_DEFs.
+       (visit_assignment): Gather ccp information for V_MUST_DEF operands.
+       (ccp_fold): Deal with RHS' that are constant and virtual.
+       (evaluate_stmt): Handle UNKNOWN_VAL likely values.
+       (dump_lattice_value): Dump UNKNOWN_VAL latticevalues.
+       (initialize): Mark statements with V_MUST_DEFs as VARYING only if the
+       V_MUST_DEF operand is VARYING. Fix comment and include VOPS when 
+       computing immediate uses.
+       (set_lattice_value): Disallow a UNKNOWN_VAL->UNDEFINED state 
+       transition.
+       (replace_vuse_in): New function.
+       (likely_value): Add check of vuse operands.
+       (get_default_value): Set the default value of virtually defined 
+       variables to UKNOWN_VAL instead of VARYING.
+
 2004-07-22  Richard Henderson  <rth@redhat.com>
 
        * expr.c (emit_push_insn): Don't use set_mem_attributes.
 
        * collect2.c (main):  Handle --no-demangle and --demangle flags.
 
+>>>>>>> 2.4547
 2004-07-13  Sebastian Pop  <pop@cri.ensmp.fr>
 
        * Makefile.in (OBJS-common): Add tree-data-ref.o.
index 9e20ccc21b4c209c0de11af25ce25f676f328f88..9003d1387842e21696d0b321043dca73172ea158 100644 (file)
@@ -1,3 +1,7 @@
+2004-07-22  Brian Booth  <bbooth@redhat.com>
+
+       * gcc.dg/tree-ssa/20040721-1.c: New test.
+
 2004-07-22  Nathan Sidwell  <nathan@codesourcery.com>
 
        * g++.dg/template/crash20.c: New.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/20040721-1.c b/gcc/testsuite/gcc.dg/tree-ssa/20040721-1.c
new file mode 100644 (file)
index 0000000..2c3ffb1
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-ccp-vops" } */
+
+/* Test to check whether global variables are being
+   constant propagated. */
+
+int G;
+
+foo (int i)
+{
+   if (i > 0)
+     G = 3;
+   else
+     G = 3;
+
+   if (G != 3)
+     link_error ();
+}
+
+main ()
+{
+   foo (0);
+   return 0;
+}
+
+/* There should be no G on the RHS of an assignment. */
+/* { dg-final { scan-tree-dump-times "= G;" 0 "ccp"} } */
index 377f18b29043ddeb5f9d5e7da53e7a6420c77b5a..38bd64a44a7295cd3a162b17ca7f4713a55bff83 100644 (file)
@@ -64,6 +64,7 @@ typedef enum
 {
   UNINITIALIZED = 0,
   UNDEFINED,
+  UNKNOWN_VAL,
   CONSTANT,
   VARYING
 } latticevalue;
@@ -139,6 +140,7 @@ static void substitute_and_fold (void);
 static value evaluate_stmt (tree);
 static void dump_lattice_value (FILE *, const char *, value);
 static bool replace_uses_in (tree, bool *);
+static bool replace_vuse_in (tree, bool *);
 static latticevalue likely_value (tree);
 static tree get_rhs (tree);
 static bool set_rhs (tree *, tree);
@@ -420,7 +422,8 @@ substitute_and_fold (void)
              print_generic_stmt (dump_file, stmt, TDF_SLIM);
            }
 
-         if (replace_uses_in (stmt, &replaced_address))
+         if (replace_uses_in (stmt, &replaced_address)
+             || replace_vuse_in (stmt, &replaced_address))
            {
              bool changed = fold_stmt (bsi_stmt_ptr (i));
              stmt = bsi_stmt(i);
@@ -482,6 +485,19 @@ visit_phi_node (tree phi)
       phi_val = *curr_val;
       break;
 
+    case UNKNOWN_VAL:
+      /* To avoid the default value of UNKNOWN_VAL overriding
+         that of its possible constant arguments, temporarily
+        set the phi node's default lattice value to be 
+        UNDEFINED. At the same time, place something other
+        than NULL_TREE in phi_val.const_val as a flag to
+        check when setting a new state for this phi node to
+        ensure that we avoid incorrect state transitions from
+        UNKNOWN_VAL to UNDEFINED. */
+      phi_val.lattice_val = UNDEFINED;
+      phi_val.const_val = phi;
+      break;
+
     case UNDEFINED:
     case UNINITIALIZED:
       phi_val.lattice_val = UNDEFINED;
@@ -550,18 +566,23 @@ visit_phi_node (tree phi)
       fprintf (dump_file, "\n\n");
     }
 
-  set_lattice_value (PHI_RESULT (phi), phi_val);
-  if (phi_val.lattice_val == VARYING)
-    DONT_SIMULATE_AGAIN (phi) = 1;
+  /* Check for an invalid change from UNKNOWN_VAL to UNDEFINED. */
+  if (phi_val.lattice_val != UNDEFINED || phi_val.const_val == NULL_TREE)
+    {
+      set_lattice_value (PHI_RESULT (phi), phi_val);
+      if (phi_val.lattice_val == VARYING)
+        DONT_SIMULATE_AGAIN (phi) = 1;
+    }
 }
 
 
 /* Compute the meet operator between VAL1 and VAL2:
 
-               any M UNDEFINED = any
-               any M VARYING   = VARYING
-               Ci  M Cj        = Ci            if (i == j)
-               Ci  M Cj        = VARYING       if (i != j)  */
+               any  M UNDEFINED     = any
+               any  M VARYING       = VARYING
+               any  M UNKNOWN_VAL   = UNKNOWN_VAL
+               Ci   M Cj            = Ci       if (i == j)
+               Ci   M Cj            = VARYING  if (i != j)  */
 static value
 cp_lattice_meet (value val1, value val2)
 {
@@ -581,6 +602,15 @@ cp_lattice_meet (value val1, value val2)
       return result;
     }
 
+  /* any M UNKNOWN_VAL = UNKNOWN_VAL.  */
+  if (val1.lattice_val == UNKNOWN_VAL 
+      || val2.lattice_val == UNKNOWN_VAL)
+    {
+      result.lattice_val = UNKNOWN_VAL;
+      result.const_val = NULL_TREE;
+      return result;
+    }
+
   /* Ci M Cj = Ci      if (i == j)
      Ci M Cj = VARYING if (i != j)  */
   if (simple_cst_equal (val1.const_val, val2.const_val) == 1)
@@ -643,8 +673,12 @@ visit_stmt (tree stmt)
   /* Now examine the statement.  If the statement is an assignment that
      produces a single output value, evaluate its RHS to see if the lattice
      value of its output has changed.  */
+  v_must_defs = V_MUST_DEF_OPS (ann);
+  v_may_defs = V_MAY_DEF_OPS (ann);
   if (TREE_CODE (stmt) == MODIFY_EXPR
-      && TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME)
+      && NUM_V_MAY_DEFS (v_may_defs) == 0
+      && (NUM_V_MUST_DEFS (v_must_defs) == 1
+          || TREE_CODE (TREE_OPERAND (stmt, 0)) == SSA_NAME))
     visit_assignment (stmt);
 
   /* Definitions made by statements other than assignments to SSA_NAMEs
@@ -681,10 +715,6 @@ visit_stmt (tree stmt)
   for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
     def_to_varying (V_MAY_DEF_RESULT (v_may_defs, i));
     
-  /* Mark all V_MUST_DEF operands VARYING.  */
-  v_must_defs = V_MUST_DEF_OPS (ann);
-  for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++)
-    def_to_varying (V_MUST_DEF_OP (v_must_defs, i));
 }
 
 
@@ -696,21 +726,50 @@ visit_assignment (tree stmt)
 {
   value val;
   tree lhs, rhs;
+  vuse_optype vuses;
+  v_must_def_optype v_must_defs;
 
   lhs = TREE_OPERAND (stmt, 0);
   rhs = TREE_OPERAND (stmt, 1);
+  vuses = STMT_VUSE_OPS (stmt);
+  v_must_defs = STMT_V_MUST_DEF_OPS (stmt);
+
+#if defined ENABLE_CHECKING
+  if (NUM_V_MAY_DEFS (STMT_V_MAY_DEF_OPS (stmt)) > 0
+      || (NUM_V_MUST_DEFS (v_must_defs) != 1
+          && TREE_CODE (lhs) != SSA_NAME))
+    abort ();
+#endif
 
-  if (TREE_THIS_VOLATILE (SSA_NAME_VAR (lhs)))
+  /* We require the SSA version number of the lhs for the value_vector.
+     Make sure we have it.  */
+  if (TREE_CODE (lhs) != SSA_NAME)
     {
-      /* Volatile variables are always VARYING.  */
-      val.lattice_val = VARYING;
-      val.const_val = NULL_TREE;
+      /* If we make it here, then stmt only has one definition:
+         a V_MUST_DEF.  */
+      lhs = V_MUST_DEF_OP (v_must_defs, 0);
     }
-  else if (TREE_CODE (rhs) == SSA_NAME)
+
+  if (TREE_CODE (rhs) == SSA_NAME)
     {
       /* For a simple copy operation, we copy the lattice values.  */
       value *nval = get_value (rhs);
       val = *nval;
+      
+      /* If lhs is not a gimple register, then it cannot take on
+         an undefined value. */
+      if (!is_gimple_reg (SSA_NAME_VAR (lhs)) 
+          && val.lattice_val == UNDEFINED)
+        val.lattice_val = UNKNOWN_VAL;      
+    }
+  else if (DECL_P (rhs) 
+           && NUM_VUSES (vuses) == 1
+           && rhs == SSA_NAME_VAR (VUSE_OP (vuses, 0)))
+    {
+      /* Same as above, but the rhs is not a gimple register and yet
+        has a known VUSE.  */
+      value *nval = get_value (VUSE_OP (vuses, 0));
+      val = *nval;
     }
   else
     {
@@ -827,11 +886,18 @@ ccp_fold (tree stmt)
   enum tree_code code = TREE_CODE (rhs);
   int kind = TREE_CODE_CLASS (code);
   tree retval = NULL_TREE;
+  vuse_optype vuses;
+  
+  vuses = STMT_VUSE_OPS (stmt);
 
   /* If the RHS is just a variable, then that variable must now have
      a constant value that we can return directly.  */
   if (TREE_CODE (rhs) == SSA_NAME)
     return get_value (rhs)->const_val;
+  else if (DECL_P (rhs) 
+           && NUM_VUSES (vuses) == 1
+           && rhs == SSA_NAME_VAR (VUSE_OP (vuses, 0)))
+    return get_value (VUSE_OP (vuses, 0))->const_val;
 
   /* Unary operators.  Note that we know the single operand must
      be a constant.  So this should almost always return a
@@ -1001,9 +1067,12 @@ evaluate_stmt (tree stmt)
   else
     {
       /* The statement produced a nonconstant value.  If the statement
-         had undefined operands, then the result of the statement should
-        be undefined.  Else the result of the statement is VARYING.  */
+         had undefined or virtual operands, then the result of the 
+        statement should be undefined or virtual respectively.  
+        Else the result of the statement is VARYING.  */
       val.lattice_val = (likelyvalue == UNDEFINED ? UNDEFINED : VARYING);
+      val.lattice_val = (likelyvalue == UNKNOWN_VAL 
+                           ? UNKNOWN_VAL : val.lattice_val);
       val.const_val = NULL_TREE;
     }
 
@@ -1024,6 +1093,9 @@ dump_lattice_value (FILE *outf, const char *prefix, value val)
     case VARYING:
       fprintf (outf, "%sVARYING", prefix);
       break;
+    case UNKNOWN_VAL:
+      fprintf (outf, "%sUNKNOWN_VAL", prefix);
+      break;
     case CONSTANT:
       fprintf (outf, "%sCONSTANT ", prefix);
       print_generic_expr (outf, val.const_val, dump_flags);
@@ -1157,6 +1229,16 @@ initialize (void)
              if (get_value (def)->lattice_val == VARYING)
                vary = 1;
            }
+         
+         /* Get the default value for each V_MUST_DEF.  */
+         v_must_defs = V_MUST_DEF_OPS (ann);
+         for (x = 0; x < NUM_V_MUST_DEFS (v_must_defs); x++)
+           {
+             tree v_must_def = V_MUST_DEF_OP (v_must_defs, x);
+             if (get_value (v_must_def)->lattice_val == VARYING)
+               vary = 1;
+           }
+         
          DONT_SIMULATE_AGAIN (stmt) = vary;
 
          /* Mark all V_MAY_DEF operands VARYING.  */
@@ -1167,15 +1249,6 @@ initialize (void)
              get_value (res)->lattice_val = VARYING;
              SET_BIT (virtual_var, SSA_NAME_VERSION (res));
            }
-           
-         /* Mark all V_MUST_DEF operands VARYING.  */
-         v_must_defs = V_MUST_DEF_OPS (ann);
-         for (x = 0; x < NUM_V_MUST_DEFS (v_must_defs); x++)
-           {
-             tree v_must_def = V_MUST_DEF_OP (v_must_defs, x);
-             get_value (v_must_def)->lattice_val = VARYING;
-             SET_BIT (virtual_var, SSA_NAME_VERSION (v_must_def));
-           }
        }
 
       for (e = bb->succ; e; e = e->succ_next)
@@ -1196,8 +1269,8 @@ initialize (void)
              for (x = 0; x < PHI_NUM_ARGS (phi); x++)
                {
                  var = PHI_ARG_DEF (phi, x);
-                 /* If one argument is virtual, the result is virtual, and
-                    therefore varying.  */
+                 /* If one argument has a V_MAY_DEF, 
+                    the result is varying.  */
                  if (TREE_CODE (var) == SSA_NAME)
                    {
                      if (TEST_BIT (virtual_var, SSA_NAME_VERSION (var)))
@@ -1216,7 +1289,7 @@ initialize (void)
 
   sbitmap_free (virtual_var);
   /* Compute immediate uses for variables we care about.  */
-  compute_immediate_uses (TDFA_USE_OPS, need_imm_uses_for);
+  compute_immediate_uses (TDFA_USE_OPS | TDFA_USE_VOPS, need_imm_uses_for);
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     dump_immediate_uses (dump_file);
@@ -1366,6 +1439,10 @@ set_lattice_value (tree var, value val)
       /* CONSTANT->UNDEFINED is never a valid state transition.  */
       if (old->lattice_val == CONSTANT)
        abort ();
+       
+      /* UNKNOWN_VAL->UNDEFINED is never a valid state transition.  */
+      if (old->lattice_val == UNKNOWN_VAL)
+       abort ();
 
       /* VARYING->UNDEFINED is generally not a valid state transition,
         except for values which are initialized to VARYING.  */
@@ -1441,6 +1518,47 @@ replace_uses_in (tree stmt, bool *replaced_addresses_p)
   return replaced;
 }
 
+/* Replace the VUSE references in statement STMT with its immediate reaching
+   definition.  Return true if the reference was replaced.  If
+   REPLACED_ADDRESSES_P is given, it will be set to true if an address
+   constant was replaced.  */
+
+static bool
+replace_vuse_in (tree stmt, bool *replaced_addresses_p)
+{
+  bool replaced = false;
+  vuse_optype vuses;
+  use_operand_p vuse;
+  value *val;
+
+  if (replaced_addresses_p)
+    *replaced_addresses_p = false;
+
+  get_stmt_operands (stmt);
+
+  vuses = STMT_VUSE_OPS (stmt);
+
+  if (NUM_VUSES (vuses) != 1)
+    return false;
+
+  vuse = VUSE_OP_PTR (vuses, 0);
+  val = get_value (USE_FROM_PTR (vuse));
+
+  if (val->lattice_val == CONSTANT
+      && TREE_CODE (stmt) == MODIFY_EXPR
+      && DECL_P (TREE_OPERAND (stmt, 1))
+      && TREE_OPERAND (stmt, 1) == SSA_NAME_VAR (USE_FROM_PTR (vuse)))
+    {
+      TREE_OPERAND (stmt, 1) = val->const_val;
+      replaced = true;
+      if (POINTER_TYPE_P (TREE_TYPE (USE_FROM_PTR (vuse))) 
+          && replaced_addresses_p)
+        *replaced_addresses_p = true;
+    }
+
+  return replaced;
+}
+
 /* Return the likely latticevalue for STMT.
 
    If STMT has no operands, then return CONSTANT.
@@ -1455,6 +1573,7 @@ static latticevalue
 likely_value (tree stmt)
 {
   use_optype uses;
+  vuse_optype vuses;
   size_t i;
   int found_constant = 0;
   stmt_ann_t ann;
@@ -1484,8 +1603,28 @@ likely_value (tree stmt)
       if (val->lattice_val == CONSTANT)
        found_constant = 1;
     }
+    
+  vuses = VUSE_OPS (ann);
+  
+  if (NUM_VUSES (vuses))
+    {
+      tree vuse = VUSE_OP (vuses, 0);
+      value *val = get_value (vuse);
+      
+      if (val->lattice_val == UNKNOWN_VAL)
+        return UNKNOWN_VAL;
+       
+#ifdef ENABLE_CHECKING
+  /* There should be no VUSE operands that are UNDEFINED. */
+  if (val->lattice_val == UNDEFINED)
+    abort ();
+#endif
+       
+      if (val->lattice_val == CONSTANT)
+       found_constant = 1;
+    }
 
-  return ((found_constant || !uses) ? CONSTANT : VARYING);
+  return ((found_constant || (!uses && !vuses)) ? CONSTANT : VARYING);
 }
 
 /* A subroutine of fold_stmt_r.  Attempts to fold *(A+O) to A[X].
@@ -2214,12 +2353,14 @@ set_rhs (tree *stmt_p, tree expr)
 
 /* Return a default value for variable VAR using the following rules:
 
-   1- Global and static variables are considered VARYING, unless they are
-      declared const.
+   1- Function arguments are considered VARYING.
+   
+   2- Global and static variables that are declared constant are
+      considered CONSTANT.
 
-   2- Function arguments are considered VARYING.
+   3- Any other virtually defined variable is considered UNKNOWN_VAL.
 
-   3- Any other value is considered UNDEFINED.  This is useful when
+   4- Any other value is considered UNDEFINED.  This is useful when
       considering PHI nodes.  PHI arguments that are undefined do not
       change the constant value of the PHI node, which allows for more
       constants to be propagated.  */
@@ -2252,10 +2393,8 @@ get_default_value (tree var)
   else if (decl_function_context (sym) != current_function_decl
            || TREE_STATIC (sym))
     {
-      /* Globals and static variables are considered VARYING, unless they
-        are declared 'const'.  */
-      val.lattice_val = VARYING;
-
+      /* Globals and static variables are considered UNKNOWN_VAL,
+         unless they are declared 'const'.  */
       if (TREE_READONLY (sym)
          && DECL_INITIAL (sym)
          && is_gimple_min_invariant (DECL_INITIAL (sym)))
@@ -2263,6 +2402,16 @@ get_default_value (tree var)
          val.lattice_val = CONSTANT;
          val.const_val = DECL_INITIAL (sym);
        }
+      else
+        {
+          val.const_val = NULL_TREE;
+         val.lattice_val = UNKNOWN_VAL;
+       }
+    }
+  else if (!is_gimple_reg (sym))
+    {
+      val.const_val = NULL_TREE;
+      val.lattice_val = UNKNOWN_VAL;
     }
   else
     {