This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[tree-ssa] Switch edge insertion patch.


This ugliness occurs when you have 2 or more nested switch stmt's and
the insertion of a stmt on an edge causes more than one of the switches
to be processed. ie, In order to create a default case for one switch,
we need to create a deafult case for a second switch.

Its pretty ugly, and the patch is equally ugly. It resolves this problem
and the problem PRE was having with pre-splitting all critical edges.

Bootstrapped and verified on x86, no new regresssions, and checked in.


Andrew




	* tree-cfg.c (handle_switch_fallthru): A New basic block is the result
	of splitting edges of nested switch stmts.
	(handle_switch_split): If a new block is created, restart the loop for
	inserting GOTO's to handle the new block.



Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.176
diff -c -p -r1.1.4.176 tree-cfg.c
*** tree-cfg.c	14 Oct 2003 17:31:33 -0000	1.1.4.176
--- tree-cfg.c	17 Oct 2003 19:24:15 -0000
*************** handle_switch_fallthru (tree sw_stmt, ba
*** 3658,3665 ****
    for (e = dest->pred; e; e = e->pred_next)
      if (e->src != new_bb)
        {
          stmt = last_stmt (e->src);
! 	if (TREE_CODE (stmt) != GOTO_EXPR)
  	  {
  	    goto_stmt = build1 (GOTO_EXPR, void_type_node, label);
  	    tmp = PENDING_STMT (e);
--- 3658,3669 ----
    for (e = dest->pred; e; e = e->pred_next)
      if (e->src != new_bb)
        {
+         /* The only way stmt can be NULL is if we are in the process of
+ 	   handling a nested switch stmt when we get here, and haven't 
+ 	   fully constructed the default case for the other one yet.  This 
+ 	   ought to be safe to ignore at this point.  */
          stmt = last_stmt (e->src);
! 	if (stmt && TREE_CODE (stmt) != GOTO_EXPR)
  	  {
  	    goto_stmt = build1 (GOTO_EXPR, void_type_node, label);
  	    tmp = PENDING_STMT (e);
*************** handle_switch_split (basic_block src, ba
*** 3762,3781 ****
  
    /* Insert a goto on all edges except the one from src to this label. */
  
    for (e = dest->pred; e ; e = e->pred_next)
      {
        if (e->src != src)
          {
  	  goto_stmt = build1 (GOTO_EXPR, void_type_node, label);
  	  tmp_tree = PENDING_STMT (e);
  	  SET_PENDING_STMT (e, NULL_TREE);
  	  bsi_insert_on_edge_immediate (e, goto_stmt, NULL, &new_bb);
  	  SET_PENDING_STMT (e, tmp_tree);
  	  e->flags = e->flags & ~EDGE_FALLTHRU;
  
- 	  /* Splitting this edge should never result in a new block.  */
- 	  if (new_bb)
- 	    abort ();
  	}
      }
  
--- 3766,3810 ----
  
    /* Insert a goto on all edges except the one from src to this label. */
  
+ restart_loop:
    for (e = dest->pred; e ; e = e->pred_next)
      {
        if (e->src != src)
          {
+ 	  tmp = bsi_last (e->src);
+ 	  goto_stmt = bsi_stmt (tmp);
+ 	  /* Dont issue a goto if it already goto's this label.  See below 
+ 	     for how this can happen to a new label.  */
+ 	  if (goto_stmt && TREE_CODE (goto_stmt) == GOTO_EXPR
+ 	      && GOTO_DESTINATION (goto_stmt) == label)
+ 	    continue;
+ 
  	  goto_stmt = build1 (GOTO_EXPR, void_type_node, label);
  	  tmp_tree = PENDING_STMT (e);
  	  SET_PENDING_STMT (e, NULL_TREE);
  	  bsi_insert_on_edge_immediate (e, goto_stmt, NULL, &new_bb);
+ 
+ 	  /* So splitting this edge *can* result in another basic block
+ 	     if there is a case label nested inside a an if construct, for
+ 	     instance. Yes, this is allowed. blah. 
+ 	     So this is ugly. The edge may no longer be in the edge list we
+ 	     have been traversing, so we have to start over.  First attach any
+ 	     pending insertions to the new edge.  This is why we need to check 
+ 	     for exisiting GOTO's to our label above.  */
+ 	  if (new_bb)
+ 	    {
+ #ifdef ENABLE_CHECKING
+ 	      /* There ought to be exactly one successor to the new block.  */
+ 	      if (new_bb->succ == NULL || new_bb->succ->succ_next != NULL)
+ 	        abort();
+ #endif
+ 	      SET_PENDING_STMT (new_bb->succ, tmp_tree);
+ 	      new_bb->succ->flags = new_bb->succ->flags & ~EDGE_FALLTHRU;
+ 	      goto restart_loop;
+ 	    }
  	  SET_PENDING_STMT (e, tmp_tree);
  	  e->flags = e->flags & ~EDGE_FALLTHRU;
  
  	}
      }
  




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]