[tree-ssa] Support threading through SWITCH_EXPRs

law@redhat.com law@redhat.com
Wed Jan 21 08:44:00 GMT 2004


[ I ended up saying up later than I originally planned :( ]

The discussion of gcc/1532 happened to catch my eye and though the 
primary issue the PR raises it out of the domain of the tree-ssa
optimizers, I did notice something the tree-ssa optimizers should have
handled better.

Specifically, there are 3 paths to the switch statement, each feeding
the switch condition a different constant.  The tree-ssa optimizers
correctly found those constants and put them into the PHI node at the
start of the block with the SWITCH_EXPR.  However, I hadn't gotten
around to supporting SWITCH_EXPR in the threading code.  So we didn't
make use of any of those constants.  Opps.

This patch fixing that problem (quite trivially I might add).


FWIW, the testcase looks like this:

inline int check(int i,int j) {
  if (i==j) return 0;
  else if (i>j) return 1;
  else return 2;
}

int foo(int i,int j) {
  switch (check(i,j)) {
  case 0: return i+j;
  case 1: return i;
  case 2: return j;
  }
}

A little analysis quickly shows that the the if statements in "check"
completely determine which case is taken in the switch statement within
"foo".

With this patch the tree-ssa optimizers are able to completely eliminate
the switch statement before handing the code off to the tree->rtl
expanders.  Whee.

Bootstrapped and regression tested on i686-pc-linux-gnu.


	* tree-ssa-dom.c (thread_across_edge): Handle SWITCH_EXPRs in the
	target block in addition to COND_EXPRs.

Index: tree-ssa-dom.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-dom.c,v
retrieving revision 1.1.2.116
diff -c -p -r1.1.2.116 tree-ssa-dom.c
*** tree-ssa-dom.c	21 Jan 2004 07:06:11 -0000	1.1.2.116
--- tree-ssa-dom.c	21 Jan 2004 08:26:43 -0000
*************** thread_across_edge (struct dom_walk_data
*** 666,672 ****
  
        /* If this is not a MODIFY_EXPR which sets an SSA_NAME to a new
  	 value, then stop our search here.  Ideally when we stop a
! 	 search we stop on a COND_EXPR.  */
        if (TREE_CODE (stmt) != MODIFY_EXPR
  	  || TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME)
  	break;
--- 666,672 ----
  
        /* If this is not a MODIFY_EXPR which sets an SSA_NAME to a new
  	 value, then stop our search here.  Ideally when we stop a
! 	 search we stop on a COND_EXPR or SWITCH_EXPR.  */
        if (TREE_CODE (stmt) != MODIFY_EXPR
  	  || TREE_CODE (TREE_OPERAND (stmt, 0)) != SSA_NAME)
  	break;
*************** thread_across_edge (struct dom_walk_data
*** 783,793 ****
        VARRAY_PUSH_TREE (bd->const_and_copies, prev_value);
      }
  
!   /* If we stopped at a COND_EXPR, then see if we know which arm will
!      be taken.  */
!   if (stmt && TREE_CODE (stmt) == COND_EXPR)
      {
!       tree cached_lhs;
        edge e1;
  
        /* Do not forward a back edge in the CFG.  This avoids short circuiting
--- 783,794 ----
        VARRAY_PUSH_TREE (bd->const_and_copies, prev_value);
      }
  
!   /* If we stopped at a COND_EXPR or SWITCH_EXPR, then see if we know which
!      arm will be taken.  */
!   if (stmt
!       && (TREE_CODE (stmt) == COND_EXPR  || TREE_CODE (stmt) == SWITCH_EXPR))
      {
!       tree cond, cached_lhs;
        edge e1;
  
        /* Do not forward a back edge in the CFG.  This avoids short circuiting
*************** thread_across_edge (struct dom_walk_data
*** 811,824 ****
  
        /* Now temporarily cprop the operands and try to find the resulting
  	 expression in the hash tables.  */
!       if (TREE_CODE_CLASS (TREE_CODE (COND_EXPR_COND (stmt))) == '<')
  	{
  	  tree dummy_cond, op0, op1;
  	  enum tree_code cond_code;
  
! 	  op0 = TREE_OPERAND (COND_EXPR_COND (stmt), 0);
! 	  op1 = TREE_OPERAND (COND_EXPR_COND (stmt), 1);
! 	  cond_code = TREE_CODE (COND_EXPR_COND (stmt));
  
  	  /* Get the current value of both operands.  */
  	  if (TREE_CODE (op0) == SSA_NAME)
--- 812,830 ----
  
        /* Now temporarily cprop the operands and try to find the resulting
  	 expression in the hash tables.  */
!       if (TREE_CODE (stmt) == COND_EXPR)
! 	cond = COND_EXPR_COND (stmt);
!       else
! 	cond = SWITCH_COND (stmt);
! 
!       if (TREE_CODE_CLASS (TREE_CODE (cond)) == '<')
  	{
  	  tree dummy_cond, op0, op1;
  	  enum tree_code cond_code;
  
! 	  op0 = TREE_OPERAND (cond, 0);
! 	  op1 = TREE_OPERAND (cond, 1);
! 	  cond_code = TREE_CODE (cond);
  
  	  /* Get the current value of both operands.  */
  	  if (TREE_CODE (op0) == SSA_NAME)
*************** thread_across_edge (struct dom_walk_data
*** 869,877 ****
        /* We can have conditionals which just test the state of a
  	 variable rather than use a relational operator.  These are
  	 simpler to handle.  */
!       else if (TREE_CODE (COND_EXPR_COND (stmt)) == SSA_NAME)
  	{
! 	  cached_lhs = COND_EXPR_COND (stmt);
  	  cached_lhs = get_value_for (cached_lhs, const_and_copies);
  	  if (cached_lhs && ! is_gimple_min_invariant (cached_lhs))
  	    cached_lhs = 0;
--- 875,883 ----
        /* We can have conditionals which just test the state of a
  	 variable rather than use a relational operator.  These are
  	 simpler to handle.  */
!       else if (TREE_CODE (cond) == SSA_NAME)
  	{
! 	  cached_lhs = cond;
  	  cached_lhs = get_value_for (cached_lhs, const_and_copies);
  	  if (cached_lhs && ! is_gimple_min_invariant (cached_lhs))
  	    cached_lhs = 0;








More information about the Gcc-patches mailing list