[tree-ssa] tidy ccp+fab passes

Richard Henderson rth@twiddle.net
Thu Feb 5 06:51:00 GMT 2004


This patch is extract of a slightly more ambitious patch that
Diego wasn't too keen on just now, but there are a number of
code cleanups that I felt were still valuable now.

 * Debugging dumps would lie.  In particular, the CONST->VARYING
   transition that's forced by set_lattice_value happened after
   the debugging dumps.  Slightly confusing to say the least...

 * Use switch statements with default abort in most places just
   in case someone adds a new lattice state.

 * Remove strlen hack in replace_uses_in.  The strlen folding bits
   don't actually use CCP data; it just follows PHI nodes.  The
   folding is instead handled by execute_fold_all_builtins.

 * Force __builtin_constant_p to be folded to 0 in 
   execute_fold_all_builtins.  We've had dom1, dom2 and ccp that
   propagate constants that run before this point, so if the arg
   is constant, it's quite likely that we know it by now.  Folding
   this to 0 now allows dom3 to remove more dead code.


r~


        * tree-ssa-ccp.c (get_value, visit_phi_node,
        visit_assignment, dump_lattice_value): Tidy.
        (evaluate_stmt): Don't do debug dump here.
        (def_to_undefined): Merge into set_lattice_value.
        (def_to_varying): Likewise, but retain as a wrapper.
        (set_lattice_value): Tidy.  Emit correct debug info.
        (replace_uses_in): Remove strlen hacks.
        (execute_fold_all_builtins): Fix DECL_BUILT_IN comparison.
        Force folding of BUILT_IN_CONSTANT_P.
        * gcc.dg/tree-ssa/ssa-ccp-10.c: Look at fab dump.

Index: tree-ssa-ccp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-ccp.c,v
retrieving revision 1.1.2.135
diff -u -p -c -r1.1.2.135 tree-ssa-ccp.c
*** tree-ssa-ccp.c	2 Feb 2004 14:55:15 -0000	1.1.2.135
--- tree-ssa-ccp.c	5 Feb 2004 06:31:09 -0000
*************** static void visit_assignment (tree);
*** 111,117 ****
  static void add_var_to_ssa_edges_worklist (tree);
  static void add_outgoing_control_edges (basic_block);
  static void add_control_edge (edge);
- static void def_to_undefined (tree);
  static void def_to_varying (tree);
  static void set_lattice_value (tree, value);
  static void simulate_block (basic_block);
--- 111,116 ----
*************** static bool replace_uses_in (tree, bool 
*** 123,129 ****
  static latticevalue likely_value (tree);
  static tree get_rhs (tree);
  static void set_rhs (tree *, tree);
! static inline value *get_value (tree);
  static value get_default_value (tree);
  static tree ccp_fold_builtin (tree, tree);
  static bool get_strlen (tree, tree *, bitmap);
--- 122,128 ----
  static latticevalue likely_value (tree);
  static tree get_rhs (tree);
  static void set_rhs (tree *, tree);
! static value *get_value (tree);
  static value get_default_value (tree);
  static tree ccp_fold_builtin (tree, tree);
  static bool get_strlen (tree, tree *, bitmap);
*************** struct tree_opt_pass pass_ccp = 
*** 219,237 ****
  
  /* Get the constant value associated with variable VAR.  */
  
! static inline value *
  get_value (tree var)
  {
    value *val;
  #if defined ENABLE_CHECKING
    if (TREE_CODE (var) != SSA_NAME)
      abort ();
  #endif
  
!   val = &(value_vector[SSA_NAME_VERSION (var)]);
    if (val->lattice_val == UNINITIALIZED)
      *val = get_default_value (var);
!     
    return val;
  }
  
--- 218,237 ----
  
  /* Get the constant value associated with variable VAR.  */
  
! static value *
  get_value (tree var)
  {
    value *val;
+ 
  #if defined ENABLE_CHECKING
    if (TREE_CODE (var) != SSA_NAME)
      abort ();
  #endif
  
!   val = &value_vector[SSA_NAME_VERSION (var)];
    if (val->lattice_val == UNINITIALIZED)
      *val = get_default_value (var);
! 
    return val;
  }
  
*************** substitute_and_fold (void)
*** 409,416 ****
  static void
  visit_phi_node (tree phi)
  {
!   int i, short_circuit = 0;
    value phi_val, *curr_val;
  
    /* If the PHI node has already been deemed to be VARYING, don't simulate
       it again.  */
--- 409,417 ----
  static void
  visit_phi_node (tree phi)
  {
!   bool short_circuit = 0;
    value phi_val, *curr_val;
+   int i;
  
    /* If the PHI node has already been deemed to be VARYING, don't simulate
       it again.  */
*************** visit_phi_node (tree phi)
*** 424,446 ****
      }
  
    curr_val = get_value (PHI_RESULT (phi));
!   if (curr_val->lattice_val == VARYING)
      {
        if (tree_dump_file && (tree_dump_flags & TDF_DETAILS))
  	fprintf (tree_dump_file, "\n   Shortcircuit. Default of VARYING.");
        short_circuit = 1;
      }
-   else
-     if (curr_val->lattice_val != CONSTANT)
-       {
- 	phi_val.lattice_val = UNDEFINED;
- 	phi_val.const_val = NULL_TREE;
-       }
-     else
-       {
- 	phi_val.lattice_val = curr_val->lattice_val;
- 	phi_val.const_val = curr_val->const_val;
-       }
  
    /* If the variable is volatile or the variable is never referenced in a
       real operand, then consider the PHI node VARYING.  */
--- 425,451 ----
      }
  
    curr_val = get_value (PHI_RESULT (phi));
!   switch (curr_val->lattice_val)
      {
+     case VARYING:
        if (tree_dump_file && (tree_dump_flags & TDF_DETAILS))
  	fprintf (tree_dump_file, "\n   Shortcircuit. Default of VARYING.");
        short_circuit = 1;
+       break;
+ 
+     case CONSTANT:
+       phi_val = *curr_val;
+       break;
+ 
+     case UNDEFINED:
+     case UNINITIALIZED:
+       phi_val.lattice_val = UNDEFINED;
+       phi_val.const_val = NULL_TREE;
+       break;
+ 
+     default:
+       abort ();
      }
  
    /* If the variable is volatile or the variable is never referenced in a
       real operand, then consider the PHI node VARYING.  */
*************** visit_phi_node (tree phi)
*** 454,462 ****
  
  	if (tree_dump_file && (tree_dump_flags & TDF_DETAILS))
  	  {
! 	    fprintf (tree_dump_file, "\n    Argument #%d (%d -> %d %sexecutable)\n",
! 		    i, e->src->index, e->dest->index,
! 		    (e->flags & EDGE_EXECUTABLE) ? "" : "not ");
  	  }
  
  	/* If the incoming edge is executable, Compute the meet operator for
--- 459,468 ----
  
  	if (tree_dump_file && (tree_dump_flags & TDF_DETAILS))
  	  {
! 	    fprintf (tree_dump_file,
! 		     "\n    Argument #%d (%d -> %d %sexecutable)\n",
! 		     i, e->src->index, e->dest->index,
! 		     (e->flags & EDGE_EXECUTABLE) ? "" : "not ");
  	  }
  
  	/* If the incoming edge is executable, Compute the meet operator for
*************** visit_assignment (tree stmt)
*** 650,657 ****
      {
        /* For a simple copy operation, we copy the lattice values.  */
        value *nval = get_value (rhs);
!       val.lattice_val = nval->lattice_val;
!       val.const_val = nval->const_val;
      }
    else
      {
--- 656,662 ----
      {
        /* For a simple copy operation, we copy the lattice values.  */
        value *nval = get_value (rhs);
!       val = *nval;
      }
    else
      {
*************** evaluate_stmt (tree stmt)
*** 944,968 ****
        val.const_val = NULL_TREE;
      }
  
-   /* Debugging dumps.  */
-   if (tree_dump_file && (tree_dump_flags & TDF_DETAILS))
-     {
-       fprintf (tree_dump_file, "Statement evaluates to ");
-       print_generic_stmt (tree_dump_file, simplified, TDF_SLIM);
-       fprintf (tree_dump_file, " which is ");
-       if (val.lattice_val == CONSTANT)
- 	{
- 	  fprintf (tree_dump_file, "constant ");
- 	  print_generic_expr (tree_dump_file, simplified, 0);
- 	}
-       else if (val.lattice_val == VARYING)
- 	fprintf (tree_dump_file, "not a constant");
-       else if (val.lattice_val == UNDEFINED)
- 	fprintf (tree_dump_file, "undefined");
- 
-       fprintf (tree_dump_file, "\n");
-     }
- 
    return val;
  }
  
--- 949,954 ----
*************** evaluate_stmt (tree stmt)
*** 972,985 ****
  static void
  dump_lattice_value (FILE *outf, const char *prefix, value val)
  {
!   if (val.lattice_val == UNDEFINED)
!     fprintf (outf, "%sUNDEFINED", prefix);
!   else if (val.lattice_val == VARYING)
!     fprintf (outf, "%sVARYING", prefix);
!   else
      {
        fprintf (outf, "%sCONSTANT ", prefix);
        print_generic_expr (outf, val.const_val, 0);
      }
  }
  
--- 958,977 ----
  static void
  dump_lattice_value (FILE *outf, const char *prefix, value val)
  {
!   switch (val.lattice_val)
      {
+     case UNDEFINED:
+       fprintf (outf, "%sUNDEFINED", prefix);
+       break;
+     case VARYING:
+       fprintf (outf, "%sVARYING", prefix);
+       break;
+     case CONSTANT:
        fprintf (outf, "%sCONSTANT ", prefix);
        print_generic_expr (outf, val.const_val, 0);
+       break;
+     default:
+       abort ();
      }
  }
  
*************** add_var_to_ssa_edges_worklist (tree var)
*** 1274,1381 ****
      }
  }
  
- /* Set the lattice value for the variable VAR to UNDEFINED.  */
- 
- static void
- def_to_undefined (tree var)
- {
-   value *value = get_value (var);
- 
- #ifdef ENABLE_CHECKING
-   /* CONSTANT->UNDEFINED is never a valid state transition.  */
-   if (value->lattice_val == CONSTANT)
-     abort ();
- 
-   /* VARYING->UNDEFINED is generally not a valid state transition,
-      except for values which are initialized to VARYING.  */
-   if (value->lattice_val == VARYING
-       && get_default_value (var).lattice_val != VARYING)
-     abort ();
- #endif
- 
-   if (value->lattice_val != UNDEFINED)
-     {
-       if (tree_dump_file && (tree_dump_flags & TDF_DETAILS))
- 	fprintf (tree_dump_file, "Lattice value changed.  Adding definition to SSA edges.\n");
- 
-       add_var_to_ssa_edges_worklist (var);
-       value->lattice_val = UNDEFINED;
-       value->const_val = NULL_TREE;
-     }
- }
- 
- 
  /* Set the lattice value for the variable VAR to VARYING.  */
  
  static void
  def_to_varying (tree var)
  {
!   value *value = get_value (var);
! 
!   if (value->lattice_val != VARYING)
!     {
!       if (tree_dump_file && (tree_dump_flags & TDF_DETAILS))
! 	fprintf (tree_dump_file, "Lattice value changed.  Adding definition to SSA edges.\n");
! 
!       add_var_to_ssa_edges_worklist (var);
!       value->lattice_val = VARYING;
!       value->const_val = NULL_TREE;
!     }
  }
  
- 
  /* Set the lattice value for variable VAR to VAL.  */
  
  static void
  set_lattice_value (tree var, value val)
  {
!   if (val.lattice_val == UNDEFINED)
!     def_to_undefined (var);
!   else if (val.lattice_val == VARYING)
!     def_to_varying (var);
!   else
!     {
!       value *old_val = get_value (var);
! 
!       /* If the RHS is a constant value that is different from a previous
! 	 value for this reference, add its SSA edge to the worklist.  */
!       if (old_val->lattice_val != CONSTANT
! 	  || !(simple_cst_equal (old_val->const_val, val.const_val)) == 1)
! 	{
! 	  if (tree_dump_file && (tree_dump_flags & TDF_DETAILS))
! 	    {
! 	      fprintf (tree_dump_file, "Lattice value changed to ");
! 	      print_generic_expr (tree_dump_file, val.const_val, 0);
! 	      fprintf (tree_dump_file, ".  Adding definition to SSA edges.\n");
! 	    }
! 
!           add_var_to_ssa_edges_worklist (var);
  
  #ifdef ENABLE_CHECKING
! 	  /* VARYING -> CONSTANT is an invalid state transition, except
! 	     for objects which start off in a VARYING state.  */
! 	  if (old_val->lattice_val == VARYING
! 	      && get_default_value (var).lattice_val != VARYING)
! 	    abort ();
  #endif
  
! 	  /* If the constant for VAR has changed, then this VAR is
! 	     really varying.  */
! 	  if (old_val->lattice_val == CONSTANT)
! 	    {
! 	      old_val->lattice_val = VARYING;
! 	      old_val->const_val = NULL_TREE;
! 	    }
! 	  else
! 	    {
! 	      old_val->lattice_val = CONSTANT;
! 	      old_val->const_val = val.const_val;
! 	    }
  	}
      }
  }
  
- 
  /* Replace USE references in statement STMT with their immediate reaching
     definition.  Return true if at least one reference was replaced.  If
     REPLACED_ADDRESSES_P is given, it will be set to true if an address
--- 1266,1334 ----
      }
  }
  
  /* Set the lattice value for the variable VAR to VARYING.  */
  
  static void
  def_to_varying (tree var)
  {
!   value val;
!   val.lattice_val = VARYING;
!   val.const_val = NULL_TREE;
!   set_lattice_value (var, val);
  }
  
  /* Set the lattice value for variable VAR to VAL.  */
  
  static void
  set_lattice_value (tree var, value val)
  {
!   value *old = get_value (var);
  
  #ifdef ENABLE_CHECKING
!   if (val.lattice_val == UNDEFINED)
!     {
!       /* CONSTANT->UNDEFINED is never a valid state transition.  */
!       if (old->lattice_val == CONSTANT)
! 	abort ();
! 
!       /* VARYING->UNDEFINED is generally not a valid state transition,
! 	 except for values which are initialized to VARYING.  */
!       if (old->lattice_val == VARYING
! 	  && get_default_value (var).lattice_val != VARYING)
! 	abort ();
!     }
!   else if (val.lattice_val == CONSTANT)
!     {
!       /* VARYING -> CONSTANT is an invalid state transition, except
! 	 for objects which start off in a VARYING state.  */
!       if (old->lattice_val == VARYING
! 	  && get_default_value (var).lattice_val != VARYING)
! 	abort ();
!     }
  #endif
  
!   /* If the constant for VAR has changed, then this VAR is really varying.  */
!   if (old->lattice_val == CONSTANT && val.lattice_val == CONSTANT
!       && !simple_cst_equal (old->const_val, val.const_val))
!     {
!       val.lattice_val = VARYING;
!       val.const_val = NULL_TREE;
!     }
! 
!   if (old->lattice_val != val.lattice_val)
!     {
!       if (tree_dump_file && (tree_dump_flags & TDF_DETAILS))
! 	{
! 	  dump_lattice_value (tree_dump_file,
! 			      "Lattice value changed to ", val);
! 	  fprintf (tree_dump_file, ".  Adding definition to SSA edges.\n");
  	}
+ 
+       add_var_to_ssa_edges_worklist (var);
+       *old = val;
      }
  }
  
  /* Replace USE references in statement STMT with their immediate reaching
     definition.  Return true if at least one reference was replaced.  If
     REPLACED_ADDRESSES_P is given, it will be set to true if an address
*************** replace_uses_in (tree stmt, bool *replac
*** 1408,1439 ****
  	}
      }
  
-   /* Some builtins like strlen may evaluate to a constant value even if
-      they have non-constant operands.  For instance,
-      'strlen (g++ ? "foo" : "bar")' will always evaluate to 3.  If the
-      statement contains a call to one of these builtins, pretend that we
-      replaced constant operands in it so that it can be handed to
-      fold_stmt().  */
-   if (!replaced
-       && (TREE_CODE (stmt) == CALL_EXPR
- 	  || (TREE_CODE (stmt) == MODIFY_EXPR
- 	      && TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)))
- 
-     {
-       tree rhs = (TREE_CODE (stmt) == MODIFY_EXPR)
- 		  ? TREE_OPERAND (stmt, 1)
- 		  : stmt;
-       tree callee = get_callee_fndecl (rhs);
- 
-       /* For now, we are only interested in handling a few builtins.  */
-       if (callee
- 	  && DECL_BUILT_IN (callee)
- 	  && DECL_BUILT_IN_CLASS (callee) != BUILT_IN_MD)
- 	replaced = (DECL_FUNCTION_CODE (callee) == BUILT_IN_STRLEN
- 	            || DECL_FUNCTION_CODE (callee) == BUILT_IN_FPUTS
- 		    || DECL_FUNCTION_CODE (callee) == BUILT_IN_FPUTS_UNLOCKED);
-     }
- 
    return replaced;
  }
  
--- 1361,1366 ----
*************** execute_fold_all_builtins (void)
*** 2309,2320 ****
  	  if (!call || TREE_CODE (call) != CALL_EXPR)
  	    continue;
  	  callee = get_callee_fndecl (call);
! 	  if (!callee || !DECL_BUILT_IN (callee))
  	    continue;
  
  	  result = ccp_fold_builtin (*stmtp, call);
  	  if (!result)
! 	    continue;
  
  	  if (tree_dump_file && (tree_dump_flags & TDF_DETAILS))
  	    {
--- 2236,2258 ----
  	  if (!call || TREE_CODE (call) != CALL_EXPR)
  	    continue;
  	  callee = get_callee_fndecl (call);
! 	  if (!callee || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL)
  	    continue;
  
  	  result = ccp_fold_builtin (*stmtp, call);
  	  if (!result)
! 	    switch (DECL_FUNCTION_CODE (callee))
! 	      {
! 	      case BUILT_IN_CONSTANT_P:
! 		/* Resolve __builtin_constant_p.  If it hasn't been
! 		   folded to integer_one_node by now, it's fairly
! 		   certain that the value simply isn't constant.  */
! 		result = integer_zero_node;
! 		break;
! 
! 	      default:
! 		continue;
! 	      }
  
  	  if (tree_dump_file && (tree_dump_flags & TDF_DETAILS))
  	    {
Index: testsuite/gcc.dg/tree-ssa/ssa-ccp-10.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/tree-ssa/Attic/ssa-ccp-10.c,v
retrieving revision 1.1.2.1
diff -u -p -c -r1.1.2.1 ssa-ccp-10.c
*** testsuite/gcc.dg/tree-ssa/ssa-ccp-10.c	27 Nov 2003 21:38:06 -0000	1.1.2.1
--- testsuite/gcc.dg/tree-ssa/ssa-ccp-10.c	5 Feb 2004 06:31:09 -0000
***************
*** 1,7 ****
  /* { dg-do compile } */
! /* { dg-options "-O1 -fdump-tree-ccp" } */
  
! /* Check that ccp folds strlen of equally long strings, and that it does not
     fail to terminate when there is a nontrivial cycle in the corresponding
     ssa graph.  */
  
--- 1,7 ----
  /* { dg-do compile } */
! /* { dg-options "-O1 -fdump-tree-fab" } */
  
! /* Check that we fold strlen of equally long strings, and that we do not
     fail to terminate when there is a nontrivial cycle in the corresponding
     ssa graph.  */
  
*************** middle:
*** 28,31 ****
  }
  
  /* There should be no calls to strlen.  */
! /* { dg-final { scan-tree-dump-times "strlen" 0 "ccp"} } */
--- 28,31 ----
  }
  
  /* There should be no calls to strlen.  */
! /* { dg-final { scan-tree-dump-times "strlen" 0 "fab"} } */



More information about the Gcc-patches mailing list