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] Removal of gotos from cfg based ir


Hello,

with cfg, ordinary gotos (not computed, local) do not carry any useful
information and their presence complicates things (e.g. having to handle
several types of edges, having to create new basic blocks sometimes when
redirecting edges, and also having to remove superfluous gotos).
Additionaly they of course consume some memory. This patch removes them
during the lifespan of the cfg, thus making all of these issues much
simpler.

The same fact is used to represent conditional expressions in more
memory efficient fashion (the only useful information from COND_EXPR is
the condition, the rest is represented by cfg).  To keep the things
consistent, I have also massaged SWITCH_EXPRs to work the same way; in
fact, it turned out to be natural to represent both of these
constructions by a single statement -- CF_EXPR; this made it possible to
simplify some of the code that previously was done twice, once for
COND_EXPRs and once for SWITCH_EXPRs.

Bootstrapped and regtested on i686 (I have made a few trivial changes
after the testing, so I am rerunning the tests now).

For Jeff:

Speed of compiling is basically unchanged (a bit faster perhaps, but the
difference is so small that it is probably just a noise).

We produce a bit fewer jumps than before; for example number of lines of
combine.c.01.rtl decreases from 158034 to 157474.

Zdenek

	* basic-block.h (EDGE_TRUE_VALUE, EDGE_FALSE_VALUE): Renamed to
	EDGE_DEFAULT_VALUE and EDGE_ZERO_VALUE, respectively.
	* cfg.c (dump_edge_info): Change bitnames for them.
	* tree-cfg.c (tree_redirect_edge_and_branch_1,
	find_taken_edge_cond_expr, find_taken_edge_switch_expr,
	find_case_label_for_value): Removed.
	(find_taken_edge_cf_expr): New.
	(make_edges): Eliminate fallthru to exit.
	(make_ctrl_stmt_edges): Nonlocal goto handling moved to
	make_goto_expr_edges.
	(make_cond_expr_edges): Replace COND_EXPR by CF_EXPR.
	(make_switch_expr_edges): Replace SWITCH_EXPR by CF_EXPR.
	(make_goto_expr_edges): Remove simple gotos.
	(cfg_remove_useless_stmts_bb): Goto removal cancelled.
	(cleanup_control_flow): Call cleanup_cf_expr_graph instead
	of cleanup_cond_expr_graph and cleanup_switch_expr_graph.
	(cleanup_cond_expr_graph, cleanup_switch_expr_graph): Removed.
	(find_taken_edge): Use find_taken_edge_cf_expr.
	(is_ctrl_stmt): Add CF_EXPR.
	(disband_cf_node, disband_cf_nodes): New.
	(delete_tree_cfg): Call disband_cf_nodes.
	(bsi_replace): Set bb for new statement.
	(tree_split_edge, thread_jumps, tree_try_redirect_by_replacing_jump,
	tree_redirect_edge_and_branch): Work over no-gotos form.
	(has_label_p): Removed.
	(tree_verify_flow_info): Check no-gotos form invariants.
	* tree-dfa.c (get_stmt_operands): Handle CF_EXPR.
	* tree-inline.c (walk_tree): Ditto.
	* tree-pretty-print.c (dump_generic_node): Ditto.
	(pp_cfg_jump, dump_implicit_edges): New.
	(dump_generic_bb_buff): Call dump_implicit_edges.
	* tree-flow.h (cleanup_cond_expr_graph, cleanup_switch_expr_graph):
	Declaration removed.
	(cleanup_cf_expr_graph, delete_tree_ssa): Declare.
	(tree-optimize.c): Add implicitly represented gotos before recreating the
	chain.
	* tree-simple.c (is_gimple_stmt): Add CF_EXPR.
	* tree-ssa-ccp.c (visit_stmt, get_rhs, set_rhs): Handle CF_EXPRs instead of
	COND_EXPRs and SWITCH_EXPRs.
	* tree-ssa-dom.c (tree_ssa_dominator_optimize_1, thread_across_edge,
	dom_opt_finalize_block, record_equivalences_from_incoming_edge,
	thread_jumps_walk_stmts, simplify_rhs_and_lookup_avail_expr,
	simplify_cond_and_lookup_avail_expr, eliminate_redundant_computations,
	optimize_stmt, lookup_avail_expr, get_eq_expr_value, avail_expr_hash,
	avail_expr_eq): Ditto.
	* tree-ssa.c (delete_tree_ssa): Export, work even if there are no
	referenced_vars.
	(rewrite_out_of_ssa): Don't call it.
	(remove_annotations_r): Handle STATEMENT_LISTs.
	* tree-ssa-dce.c (stmt_useful_p): Remove unnecesary COND_EXPR handling.
	* tree.c (tree_node_kind_names): Add cf_exprs.
	(tree_size, tree_node_structure): Add CF_EXPR.
	(enum tree_node_structure_enum): Add TS_CF_EXPR.
	(make_node): Abort for CF_EXPRs.
	(cf_expr_elt_check_failed, make_cf_expr): New.
	* tree.def (CF_EXPR): New.
	* tree.h (CF_EXPR_ELT_CHECK): New.
	(cf_expr_elt_check_failed): Declare.
	(EXPR_LOCUS, SET_EXPR_LOCUS, EXPR_FILENAME, EXPR_LINENO): Handle
	CF_EXPRs.
	(struct cf_alt_d, struct tree_cf_expr): New.
	(CF_EXPR_COND, CF_EXPR_CAPACITY, CF_EXPR_N_ALTS, CF_EXPR_ALT,
	CF_EXPR_ALT_LOW, CF_EXPR_ALT_HIGH, CF_EXPR_ALT_EDGE): New.
	(union tree_node): Add cf_expr field.
	(make_cf_expr): Declare.
	(tree_node_kind): Add cf_expr_kind.

Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/basic-block.h,v
retrieving revision 1.153.2.36
diff -c -3 -p -r1.153.2.36 basic-block.h
*** basic-block.h	12 Nov 2003 22:06:24 -0000	1.153.2.36
--- basic-block.h	14 Nov 2003 00:08:09 -0000
*************** typedef struct edge_def {
*** 156,164 ****
  #define EDGE_IRREDUCIBLE_LOOP	128	/* Part of irreducible loop.  */
  #define EDGE_SIBCALL		256	/* Edge from sibcall to exit.  */
  #define EDGE_LOOP_EXIT		512	/* Exit of a loop.  */
! #define EDGE_TRUE_VALUE		1024	/* Edge taken when controlling
! 					   predicate is non zero.  */
! #define EDGE_FALSE_VALUE	2048	/* Edge taken when controlling
  					   predicate is zero.  */
  #define EDGE_EXECUTABLE		4096	/* Edge is executable.  Only
  					   valid during SSA-CCP.  */
--- 156,164 ----
  #define EDGE_IRREDUCIBLE_LOOP	128	/* Part of irreducible loop.  */
  #define EDGE_SIBCALL		256	/* Edge from sibcall to exit.  */
  #define EDGE_LOOP_EXIT		512	/* Exit of a loop.  */
! #define EDGE_DEFAULT_VALUE	1024	/* Edge taken when no other alternative
! 					   matches.  */
! #define EDGE_ZERO_VALUE		2048	/* Edge taken when controlling
  					   predicate is zero.  */
  #define EDGE_EXECUTABLE		4096	/* Edge is executable.  Only
  					   valid during SSA-CCP.  */
Index: cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfg.c,v
retrieving revision 1.34.2.16
diff -c -3 -p -r1.34.2.16 cfg.c
*** cfg.c	12 Nov 2003 22:06:24 -0000	1.34.2.16
--- cfg.c	14 Nov 2003 00:08:09 -0000
*************** dump_edge_info (FILE *file, edge e, int 
*** 647,653 ****
        static const char * const bitnames[] = {
  	"fallthru", "ab", "abcall", "eh", "fake", "dfs_back",
  	"can_fallthru", "irreducible", "sibcall", "loop_exit",
! 	"true", "false", "exec"
        };
        int comma = 0;
        int i, flags = e->flags;
--- 647,653 ----
        static const char * const bitnames[] = {
  	"fallthru", "ab", "abcall", "eh", "fake", "dfs_back",
  	"can_fallthru", "irreducible", "sibcall", "loop_exit",
! 	"default", "zero", "exec"
        };
        int comma = 0;
        int i, flags = e->flags;
Index: tree-cfg.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-cfg.c,v
retrieving revision 1.1.4.213
diff -c -3 -p -r1.1.4.213 tree-cfg.c
*** tree-cfg.c	13 Nov 2003 20:55:13 -0000	1.1.4.213
--- tree-cfg.c	14 Nov 2003 00:08:09 -0000
*************** static void make_exit_edges (basic_block
*** 105,111 ****
  static void make_cond_expr_edges (basic_block);
  static void make_switch_expr_edges (basic_block);
  static void make_goto_expr_edges (basic_block);
- static edge tree_redirect_edge_and_branch_1 (edge, basic_block, bool);
  static edge tree_redirect_edge_and_branch (edge, basic_block);
  
  /* Various helpers.  */
--- 105,110 ----
*************** static struct loops *tree_loop_optimizer
*** 117,130 ****
  static void tree_loop_optimizer_finalize (struct loops *, FILE *);
  static bool thread_jumps (void);
  static bool tree_forwarder_block_p (basic_block);
  
  /* Flowgraph optimization and cleanup.  */
  
  static void remove_bb (basic_block);
  static bool cleanup_control_flow (void);
- static edge find_taken_edge_cond_expr (basic_block, tree);
- static edge find_taken_edge_switch_expr (basic_block, tree);
- static tree find_case_label_for_value (tree, tree);
  static int phi_alternatives_equal (basic_block, edge, edge);
  
  /* Location to track pending stmt for edge insertion.  */
--- 116,127 ----
  static void tree_loop_optimizer_finalize (struct loops *, FILE *);
  static bool thread_jumps (void);
  static bool tree_forwarder_block_p (basic_block);
+ static edge find_taken_edge_cf_expr (basic_block, tree);
  
  /* Flowgraph optimization and cleanup.  */
  
  static void remove_bb (basic_block);
  static bool cleanup_control_flow (void);
  static int phi_alternatives_equal (basic_block, edge, edge);
  
  /* Location to track pending stmt for edge insertion.  */
*************** static void
*** 448,453 ****
--- 445,451 ----
  make_edges (void)
  {
    basic_block bb;
+   edge e;
  
    /* Create an edge from entry to the first block with executable
       statements in it.  */
*************** make_edges (void)
*** 476,481 ****
--- 474,502 ----
  	make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
      }
  
+   /* If there is a fallthru edge to exit out of the last block, transform it
+      to a return statement.  */
+   for (e = EXIT_BLOCK_PTR->prev_bb->succ; e; e = e->succ_next)
+     if (e->flags & EDGE_FALLTHRU)
+       break;
+   if (e && e->dest == EXIT_BLOCK_PTR)
+     {
+       block_stmt_iterator bsi;
+       tree x;
+ 
+       /* ??? Can we have multiple outgoing edges here?  COND_EXPR
+ 	 always has two gotos, and I can't think how one would have
+ 	 achived this via EH.  */
+       if (e != EXIT_BLOCK_PTR->prev_bb->succ || e->succ_next)
+ 	abort ();
+ 	
+       x = build (RETURN_EXPR, void_type_node, NULL_TREE);
+       bsi = bsi_last (EXIT_BLOCK_PTR->prev_bb);
+       bsi_insert_after (&bsi, x, BSI_NEW_STMT);
+ 
+       e->flags &= ~EDGE_FALLTHRU;
+     }
+ 
    /* We do not care about fake edges, so remove any that the CFG
       builder inserted for completeness.  */
    remove_fake_edges ();
*************** make_ctrl_stmt_edges (basic_block bb)
*** 505,515 ****
      {
      case GOTO_EXPR:
        make_goto_expr_edges (bb);
- 
-       /* If this is potentially a nonlocal goto, then this should also
- 	 create an edge to the exit block.   */
-       if (nonlocal_goto_p (last))
- 	make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL);
        break;
  
      case RETURN_EXPR:
--- 526,531 ----
*************** make_exit_edges (basic_block bb)
*** 603,614 ****
  static void
  make_cond_expr_edges (basic_block bb)
  {
!   tree entry = last_stmt (bb);
    basic_block then_bb, else_bb;
    tree then_label, else_label;
  
  #if defined ENABLE_CHECKING
!   if (entry == NULL_TREE || TREE_CODE (entry) != COND_EXPR)
      abort ();
  #endif
  
--- 619,632 ----
  static void
  make_cond_expr_edges (basic_block bb)
  {
!   block_stmt_iterator last = bsi_last (bb);
!   tree entry = bsi_stmt (last);
    basic_block then_bb, else_bb;
    tree then_label, else_label;
+   tree cf_expr;
  
  #if defined ENABLE_CHECKING
!   if (TREE_CODE (entry) != COND_EXPR)
      abort ();
  #endif
  
*************** make_cond_expr_edges (basic_block bb)
*** 617,625 ****
    else_label = GOTO_DESTINATION (COND_EXPR_ELSE (entry));
    then_bb = label_to_block (then_label);
    else_bb = label_to_block (else_label);
  
!   make_edge (bb, then_bb, EDGE_TRUE_VALUE);
!   make_edge (bb, else_bb, EDGE_FALSE_VALUE);
  }
  
  /* Create the edges for a SWITCH_EXPR starting at block BB.
--- 635,645 ----
    else_label = GOTO_DESTINATION (COND_EXPR_ELSE (entry));
    then_bb = label_to_block (then_label);
    else_bb = label_to_block (else_label);
+   cf_expr = make_cf_expr (COND_EXPR_COND (entry), 0);
+   bsi_replace (&last, cf_expr);
  
!   make_edge (bb, then_bb, EDGE_DEFAULT_VALUE);
!   make_edge (bb, else_bb, EDGE_ZERO_VALUE);
  }
  
  /* Create the edges for a SWITCH_EXPR starting at block BB.
*************** make_cond_expr_edges (basic_block bb)
*** 629,647 ****
  static void
  make_switch_expr_edges (basic_block bb)
  {
!   tree entry = last_stmt (bb);
    size_t i, n;
    tree vec;
  
    vec = SWITCH_LABELS (entry);
    n = TREE_VEC_LENGTH (vec);
  
    for (i = 0; i < n; ++i)
      {
!       tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i));
!       basic_block label_bb = label_to_block (lab);
!       make_edge (bb, label_bb, 0);
      }
  }
  
  basic_block
--- 649,714 ----
  static void
  make_switch_expr_edges (basic_block bb)
  {
!   block_stmt_iterator last = bsi_last (bb);
!   tree entry = bsi_stmt (last);
    size_t i, n;
+   unsigned alts;
    tree vec;
+   tree cf_expr;
+   tree lab;
+   basic_block label_bb;
+   edge e;
  
    vec = SWITCH_LABELS (entry);
    n = TREE_VEC_LENGTH (vec);
  
+   alts = 0;
+   for (i = 0; i < n; ++i)
+     {
+       if (CASE_LOW (TREE_VEC_ELT (vec, i)) == NULL)
+ 	continue;
+ 
+       if (CASE_HIGH (TREE_VEC_ELT (vec, i)) == NULL
+ 	  && integer_zerop (CASE_LOW (TREE_VEC_ELT (vec, i))))
+ 	continue;
+ 
+       alts++;
+     }
+   cf_expr = make_cf_expr (SWITCH_COND (entry), alts);
+   CF_EXPR_N_ALTS (cf_expr) = alts;
+ 
+   alts = 0;
    for (i = 0; i < n; ++i)
      {
!       lab = CASE_LABEL (TREE_VEC_ELT (vec, i));
!       label_bb = label_to_block (lab);
! 
!       e = find_edge (bb, label_bb);
!       if (!e)
! 	e = make_edge (bb, label_bb, 0);
!       if (!e)
! 	abort ();
! 
!       if (CASE_LOW (TREE_VEC_ELT (vec, i)) == NULL)
! 	{
! 	  e->flags |= EDGE_DEFAULT_VALUE;
! 	  continue;
! 	}
! 
!       if (CASE_HIGH (TREE_VEC_ELT (vec, i)) == NULL
! 	  && integer_zerop (CASE_LOW (TREE_VEC_ELT (vec, i))))
! 	{
! 	  e->flags |= EDGE_ZERO_VALUE;
! 	  continue;
! 	}
! 
!       CF_EXPR_ALT_LOW (cf_expr, alts) = CASE_LOW (TREE_VEC_ELT (vec, i));
!       CF_EXPR_ALT_HIGH (cf_expr, alts) = CASE_HIGH (TREE_VEC_ELT (vec, i));
!       CF_EXPR_ALT_EDGE (cf_expr, alts) = e;
!       alts++;
      }
+ 
+   bsi_replace (&last, cf_expr);
  }
  
  basic_block
*************** make_goto_expr_edges (basic_block bb)
*** 657,666 ****
  {
    tree goto_t, dest;
    basic_block target_bb;
-   int edge_flags;
    int for_call;
  
!   goto_t = last_stmt (bb);
  
    /* If the last statement is not a GOTO (i.e., it is a RETURN_EXPR,
       CALL_EXPR or MODIFY_EXPR), then the edge is an abnormal edge resulting
--- 724,733 ----
  {
    tree goto_t, dest;
    basic_block target_bb;
    int for_call;
+   block_stmt_iterator last = bsi_last (bb);
  
!   goto_t = bsi_stmt (last);
  
    /* If the last statement is not a GOTO (i.e., it is a RETURN_EXPR,
       CALL_EXPR or MODIFY_EXPR), then the edge is an abnormal edge resulting
*************** make_goto_expr_edges (basic_block bb)
*** 669,675 ****
      {
        dest = error_mark_node;
        for_call = 1;
-       edge_flags = EDGE_ABNORMAL;
      }
    else
      {
--- 736,741 ----
*************** make_goto_expr_edges (basic_block bb)
*** 679,691 ****
        /* A GOTO to a local label creates normal edges.  */
        if (simple_goto_p (goto_t))
  	{
! 	  make_edge (bb, label_to_block (dest), 0);
  	  return;
  	}
  
!       /* If we reach here, then we either have a computed goto or
! 	 a nonlocal goto.  */
!       edge_flags = EDGE_ABNORMAL;
      }
  
    /* Look for the block starting with the destination label.  In the
--- 745,765 ----
        /* A GOTO to a local label creates normal edges.  */
        if (simple_goto_p (goto_t))
  	{
! 	  make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
! 	  bsi_remove (&last);
  	  return;
  	}
  
!       /* If this is potentially a nonlocal goto, then this should
! 	 create an edge to the exit block.   */
!       if (nonlocal_goto_p (goto_t))
! 	make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL);
! 
!       /* Nothing more to do for nonlocal gotos. */
!       if (TREE_CODE (dest) == LABEL_DECL)
! 	return;
! 
!       /* Computed gotos remain.  */
      }
  
    /* Look for the block starting with the destination label.  In the
*************** make_goto_expr_edges (basic_block bb)
*** 702,710 ****
  	  if (TREE_CODE (target) != LABEL_EXPR)
  	    break;
  
- 	  if (TREE_CODE (dest) == LABEL_DECL)
- 	    continue;
- 
  	  if (
  	      /* Computed GOTOs.  Make an edge to every label block that has
  		 been marked as a potential target for a computed goto.  */
--- 776,781 ----
*************** make_goto_expr_edges (basic_block bb)
*** 714,720 ****
  		 goto.  */
  	      || (NONLOCAL_LABEL (LABEL_EXPR_LABEL (target)) && for_call == 1))
  	    {
! 	      make_edge (bb, target_bb, edge_flags);
  	      break;
  	    }
  	}
--- 785,791 ----
  		 goto.  */
  	      || (NONLOCAL_LABEL (LABEL_EXPR_LABEL (target)) && for_call == 1))
  	    {
! 	      make_edge (bb, target_bb, EDGE_ABNORMAL);
  	      break;
  	    }
  	}
*************** cfg_remove_useless_stmts_bb (basic_block
*** 1284,1356 ****
  {
    block_stmt_iterator bsi;
    tree stmt = NULL_TREE;
-   tree *gotos[2], *pstmt;
-   int n_gotos, n_rem_gotos;
    tree cond, var = NULL_TREE, val = NULL_TREE;
    struct var_ann_d *ann;
  
!   /* Check whether we come here from a condition, and if so, get the
       condition.  */
!   if (bb->pred && !bb->pred->pred_next
!       && (bb->pred->flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
!     {
!       cond = COND_EXPR_COND (last_stmt (bb->pred->src));
!       if (bb->pred->flags & EDGE_FALSE_VALUE)
! 	cond = invert_truthvalue (cond);
  
!       if (TREE_CODE (cond) == VAR_DECL
! 	  || TREE_CODE (cond) == PARM_DECL)
! 	{
! 	  var = cond;
! 	  val = convert (TREE_TYPE (cond), integer_zero_node);
! 	}
!       else if ((TREE_CODE (cond) == EQ_EXPR)
! 	       && (TREE_CODE (TREE_OPERAND (cond, 0)) == VAR_DECL
! 		   || TREE_CODE (TREE_OPERAND (cond, 0)) == PARM_DECL)
! 	       && (TREE_CODE (TREE_OPERAND (cond, 1)) == VAR_DECL
! 		   || TREE_CODE (TREE_OPERAND (cond, 1)) == PARM_DECL
! 		   || TREE_CONSTANT (TREE_OPERAND (cond, 1))))
! 	{
! 	  var = TREE_OPERAND (cond, 0);
! 	  val = TREE_OPERAND (cond, 1);
! 	}
  
!       if (var)
! 	{
! 	  /* Only work for normal local variables.  */
! 	  ann = var_ann (var);
! 	  if (!ann
! 	      || ann->may_aliases
! 	      || TREE_ADDRESSABLE (var))
! 	    var = NULL_TREE;
  
! 	  if (! TREE_CONSTANT (val))
! 	    {
! 	      ann = var_ann (val);
! 	      if (!ann
! 		  || ann->may_aliases
! 		  || TREE_ADDRESSABLE (val))
! 		val = NULL_TREE;
! 	    }
! 	}
  
!       /* Ignore floating point variables, since comparison behaves weird for
! 	 them.  */
!       if (var
! 	  && FLOAT_TYPE_P (TREE_TYPE (var)))
! 	var = NULL_TREE;
      }
  
    for (bsi = bsi_start (bb); !bsi_end_p (bsi);)
      {
        stmt = bsi_stmt (bsi);
  
-       if (!var)
- 	{
- 	  bsi_next (&bsi);
- 	  continue;
- 	}
- 
        /* If the THEN/ELSE clause merely assigns a value to a variable/parameter
  	 which is already known to contain that value, then remove the useless
  	 THEN/ELSE clause.  */
--- 1355,1426 ----
  {
    block_stmt_iterator bsi;
    tree stmt = NULL_TREE;
    tree cond, var = NULL_TREE, val = NULL_TREE;
    struct var_ann_d *ann;
  
!   /* Check whether we come here from a CF_EXPR, and if so, get the
       condition.  */
!   if (!bb->pred
!       || bb->pred->pred_next
!       || !(bb->pred->flags & (EDGE_DEFAULT_VALUE | EDGE_ZERO_VALUE)))
!     return;
  
!   stmt = last_stmt (bb->pred->src);
!   cond = CF_EXPR_COND (stmt);
!   if (CF_EXPR_N_ALTS (stmt) != 0)
!     return;
  
!   if (bb->pred->flags & EDGE_ZERO_VALUE)
!     {
!       if (TREE_CODE (TREE_TYPE (cond)) != BOOLEAN_TYPE)
! 	return;
!       cond = invert_truthvalue (cond);
!     }
  
!   if (TREE_CODE (cond) == VAR_DECL
!       || TREE_CODE (cond) == PARM_DECL)
!     {
!       var = cond;
!       val = convert (TREE_TYPE (cond), integer_zero_node);
!     }
!   else if ((TREE_CODE (cond) == EQ_EXPR)
! 	   && (TREE_CODE (TREE_OPERAND (cond, 0)) == VAR_DECL
! 	       || TREE_CODE (TREE_OPERAND (cond, 0)) == PARM_DECL)
! 	   && (TREE_CODE (TREE_OPERAND (cond, 1)) == VAR_DECL
! 	       || TREE_CODE (TREE_OPERAND (cond, 1)) == PARM_DECL
! 	       || TREE_CONSTANT (TREE_OPERAND (cond, 1))))
!     {
!       var = TREE_OPERAND (cond, 0);
!       val = TREE_OPERAND (cond, 1);
!     }
!   else
!     return;
! 
!   /* Only work for normal local variables.  */
!   ann = var_ann (var);
!   if (!ann
!       || ann->may_aliases
!       || TREE_ADDRESSABLE (var))
!     return;
  
!   if (! TREE_CONSTANT (val))
!     {
!       ann = var_ann (val);
!       if (!ann
! 	  || ann->may_aliases
! 	  || TREE_ADDRESSABLE (val))
! 	val = NULL_TREE;
      }
  
+   /* Ignore floating point variables, since comparison behaves weirdly for
+      them.  */
+   if (FLOAT_TYPE_P (TREE_TYPE (var)))
+     return;
+ 
    for (bsi = bsi_start (bb); !bsi_end_p (bsi);)
      {
        stmt = bsi_stmt (bsi);
  
        /* If the THEN/ELSE clause merely assigns a value to a variable/parameter
  	 which is already known to contain that value, then remove the useless
  	 THEN/ELSE clause.  */
*************** cfg_remove_useless_stmts_bb (basic_block
*** 1369,1430 ****
  	      && (TREE_OPERAND (stmt, 0) == var
  		  || TREE_OPERAND (stmt, 0) == val
  		  || TREE_CODE (TREE_OPERAND (stmt, 1)) == VA_ARG_EXPR)))
! 	var = NULL_TREE;
    
        bsi_next (&bsi);
      }
- 
-   if (!stmt)
-     return;
- 
-   /* Remove useless GOTOs from COND_EXPRs.  Other useless gotos could be
-      removed by cfg cleanup, but it is not done currently, so do it here
-      also.  */
-   if (TREE_CODE (stmt) == GOTO_EXPR
-       && (bb->succ->flags & EDGE_ABNORMAL) == 0)
-     {
-       gotos[0] = &stmt;
-       n_gotos = 1;
-     }
-   else if (TREE_CODE (stmt) == COND_EXPR
- 	   && (bb->succ->flags & EDGE_ABNORMAL) == 0
- 	   && (bb->succ->succ_next->flags & EDGE_ABNORMAL) == 0)
-     {
-       gotos[0] = &COND_EXPR_THEN (stmt);
-       gotos[1] = &COND_EXPR_ELSE (stmt);
-       n_gotos = 2;
-     }
-   else
-     return;
- 
-   n_rem_gotos = n_gotos;
-   while (n_gotos--)
-     {
-       pstmt = gotos[n_gotos];
-       stmt = *pstmt;
- 
-       if (TREE_CODE (GOTO_DESTINATION (stmt)) != LABEL_DECL)
- 	continue;
- 
-       if (label_to_block (GOTO_DESTINATION (stmt)) != bb->next_bb)
- 	continue;
- 
-       *pstmt = build_empty_stmt ();
-       n_rem_gotos--;
-     }
- 
-   /* The statement does nothing, remove it completely.  */
-   if (!n_rem_gotos)
-     {
-       bsi = bsi_last (bb);
-       bsi_remove (&bsi);
- 
-       if (bb->succ->succ_next)
- 	abort ();
- 
-       bb->succ->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
-       bb->succ->flags |= EDGE_FALLTHRU;
-     }
  }
  
  /* A cfg-aware version of remove_useless_stmts_and_vars.  */
--- 1439,1448 ----
  	      && (TREE_OPERAND (stmt, 0) == var
  		  || TREE_OPERAND (stmt, 0) == val
  		  || TREE_CODE (TREE_OPERAND (stmt, 1)) == VA_ARG_EXPR)))
! 	return;
    
        bsi_next (&bsi);
      }
  }
  
  /* A cfg-aware version of remove_useless_stmts_and_vars.  */
*************** cleanup_control_flow (void)
*** 1635,1662 ****
    basic_block bb;
    block_stmt_iterator bsi;
    bool retval = false;
  
    FOR_EACH_BB (bb)
      {
        bsi = bsi_last (bb);
  
!       if (!bsi_end_p (bsi))
! 	{
! 	  enum tree_code code = TREE_CODE (bsi_stmt (bsi));
! 	  if (code == COND_EXPR)
! 	    retval |= cleanup_cond_expr_graph (bb, bsi);
! 	  else if (code == SWITCH_EXPR)
! 	    retval |= cleanup_switch_expr_graph (bb, bsi);
! 	}
      }
    return retval;
  }
  
! /* Disconnect an unreachable block in the conditional expression starting
!    at block BB.  */
  
  bool
! cleanup_cond_expr_graph (basic_block bb, block_stmt_iterator bsi)
  {
    tree val;
    edge taken_edge;
--- 1653,1681 ----
    basic_block bb;
    block_stmt_iterator bsi;
    bool retval = false;
+   enum tree_code code;
  
    FOR_EACH_BB (bb)
      {
        bsi = bsi_last (bb);
  
!       if (bsi_end_p (bsi))
! 	continue;
! 
!       code = TREE_CODE (bsi_stmt (bsi));
! 
!       if (code == CF_EXPR)
! 	retval |= cleanup_cf_expr_graph (bb, bsi);
      }
+ 
    return retval;
  }
  
! /* Disconnect an unreachable block(s) in the control flow expression starting
!    at block BB and pointed by BSI.  */
  
  bool
! cleanup_cf_expr_graph (basic_block bb, block_stmt_iterator bsi)
  {
    tree val;
    edge taken_edge;
*************** cleanup_cond_expr_graph (basic_block bb,
*** 1665,1671 ****
  
  #if defined ENABLE_CHECKING
    if (cond_expr == NULL_TREE
!       || TREE_CODE (cond_expr) != COND_EXPR
        || !bb->succ)
      abort ();
  #endif
--- 1684,1690 ----
  
  #if defined ENABLE_CHECKING
    if (cond_expr == NULL_TREE
!       || TREE_CODE (cond_expr) != CF_EXPR
        || !bb->succ)
      abort ();
  #endif
*************** cleanup_cond_expr_graph (basic_block bb,
*** 1674,1680 ****
      {
        edge e, next;
  
!       val = COND_EXPR_COND (cond_expr);
        taken_edge = find_taken_edge (bb, val);
        if (!taken_edge)
  	return false;
--- 1693,1699 ----
      {
        edge e, next;
  
!       val = CF_EXPR_COND (cond_expr);
        taken_edge = find_taken_edge (bb, val);
        if (!taken_edge)
  	return false;
*************** cleanup_cond_expr_graph (basic_block bb,
*** 1693,1766 ****
    else
      taken_edge = bb->succ;
  
!   if (taken_edge->flags & EDGE_TRUE_VALUE)
!     bsi_replace (&bsi, COND_EXPR_THEN (cond_expr));
!   else if (taken_edge->flags & EDGE_FALSE_VALUE)
!     bsi_replace (&bsi, COND_EXPR_ELSE (cond_expr));
!   else
!     abort ();
! 
!   taken_edge->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
! 
!   return retval;
! }
! 
! /* Disconnect unreachable blocks in the 'switch' expression starting at
!    block SWITCH_BB.
! 
!    If the switch condition of the SWITCH_EXPR node in block SWITCH_BB is
!    constant, disconnect all the subgraphs for all the case labels that will
!    never be taken.  */
! 
! bool
! cleanup_switch_expr_graph (basic_block bb, block_stmt_iterator bsi)
! {
!   tree switch_expr = bsi_stmt (bsi);
!   tree switch_val, taken_case;
!   basic_block dest_bb;
!   bool retval;
! 
! #if defined ENABLE_CHECKING
!   if (switch_expr == NULL_TREE || TREE_CODE (switch_expr) != SWITCH_EXPR)
!     abort ();
! #endif
! 
!   retval = false;
!   if (bb->succ->succ_next)
!     {
!       edge e, next;
! 
!       /* Multiple destination edges.  If we've got a integer constant,
! 	 we can look up the value in the switch condition and replace.  */
!       switch_val = SWITCH_COND (switch_expr);
!       if (TREE_CODE (switch_val) != INTEGER_CST)
! 	return retval;
! 
!       taken_case = find_case_label_for_value (switch_expr, switch_val);
!       dest_bb = label_to_block (CASE_LABEL (taken_case));
! 
!       /* Remove all the edges that will never be taken.  */
!       for (e = bb->succ; e ; e = next)
! 	{
! 	  next = e->succ_next;
! 	  if (e->dest != dest_bb)
!             {
! 	      ssa_remove_edge (e);
! 	      retval = true;
! 	    }
! 	}
!     }
!   else
!     {
!       /* There is only one destination edge, which means that all of
! 	 the labels go to the same place.  */
!       dest_bb = bb->succ->dest;
!       taken_case = TREE_VEC_ELT (SWITCH_LABELS (switch_expr), 0);
!     }
! 
!   /* Simplify the SWITCH_EXPR itself.  */
!   taken_case = build (GOTO_EXPR, void_type_node, CASE_LABEL (taken_case));
!   bsi_replace (&bsi, taken_case);
  
    return retval;
  }
--- 1712,1720 ----
    else
      taken_edge = bb->succ;
  
!   bsi_remove (&bsi);
!   taken_edge->flags &= ~(EDGE_DEFAULT_VALUE | EDGE_ZERO_VALUE);
!   taken_edge->flags |= EDGE_FALLTHRU;
  
    return retval;
  }
*************** find_taken_edge (basic_block bb, tree va
*** 1786,1887 ****
    if (val == NULL || !really_constant_p (val))
      return NULL;
  
!   if (TREE_CODE (stmt) == COND_EXPR)
!     return find_taken_edge_cond_expr (bb, val);
! 
!   if (TREE_CODE (stmt) == SWITCH_EXPR)
!     return find_taken_edge_switch_expr (bb, val);
  
    return bb->succ;
  }
  
! /* Given a constant value VAL and the entry block BB to a COND_EXPR
!    statement, determine which of the two edges will be taken out of the
!    block.  Return NULL if either edge may be taken.  */
  
  static edge
! find_taken_edge_cond_expr (basic_block bb, tree val)
  {
-   bool always_false;
-   bool always_true;
    edge e;
  
!   /* Determine which branch of the if() will be taken.  */
!   always_false = integer_zerop (val);
!   always_true = integer_nonzerop (val);
! 
!   /* If VAL is a constant but it can't be reduced to a 0 or a 1, then
!      we don't really know which edge will be taken at runtime.  This
!      may happen when comparing addresses (e.g., if (&var1 == 4))  */
!   if (!always_false && !always_true)
!     return NULL;
! 
!   for (e = bb->succ; e; e = e->succ_next)
!     if (((e->flags & EDGE_TRUE_VALUE) && always_true)
! 	|| ((e->flags & EDGE_FALSE_VALUE) && always_false))
!       return e;
! 
!   /* There always should be an edge that is taken.  */
!   abort ();
! }
! 
! /* Given a constant value VAL and the entry block BB to a SWITCH_EXPR
!    statement, determine which edge will be taken out of the block.  Return
!    NULL if any edge may be taken.  */
! 
! static edge
! find_taken_edge_switch_expr (basic_block bb, tree val)
! {
!   tree switch_expr, taken_case;
!   basic_block dest_bb;
!   edge e;
  
    if (TREE_CODE (val) != INTEGER_CST)
      return NULL;
  
!   switch_expr = last_stmt (bb);
!   taken_case = find_case_label_for_value (switch_expr, val);
!   dest_bb = label_to_block (CASE_LABEL (taken_case));
! 
!   e = find_edge (bb, dest_bb);
!   if (!e)
!     abort ();
!   return e;
! }
! 
! /* Return the CASE_LABEL_EXPR that SWITCH_EXPR will take for VAL.  */
! 
! static tree
! find_case_label_for_value (tree switch_expr, tree val)
! {
!   tree vec = SWITCH_LABELS (switch_expr);
!   size_t i, n = TREE_VEC_LENGTH (vec);
!   tree default_case = NULL;
! 
!   for (i = 0; i < n; ++i)
      {
!       tree t = TREE_VEC_ELT (vec, i);
  
!       if (CASE_LOW (t) == NULL)
! 	default_case = t;
!       else if (CASE_HIGH (t) == NULL)
  	{
  	  /* A `normal' case label.  */
! 	  if (simple_cst_equal (CASE_LOW (t), val) == 1)
! 	    return t;
  	}
        else
  	{
  	  /* A case range.  We can only handle integer ranges.  */
! 	  if (tree_int_cst_compare (CASE_LOW (t), val) <= 0
! 	      && tree_int_cst_compare (CASE_HIGH (t), val) >= 0)
! 	    return t;
  	}
      }
  
!   if (!default_case)
!     abort ();
!   return default_case;
  }
  
  /* If all the phi nodes in DEST have alternatives for E1 and E2 and
--- 1740,1802 ----
    if (val == NULL || !really_constant_p (val))
      return NULL;
  
!   if (TREE_CODE (stmt) == CF_EXPR)
!     return find_taken_edge_cf_expr (bb, val);
  
    return bb->succ;
  }
  
! /* Given a constant value VAL and the entry block BB to a CF_EXPR
!    statement, determine which of the edges will be taken out of the
!    block.  Return NULL if more than one edge may be taken.  */
  
  static edge
! find_taken_edge_cf_expr (basic_block bb, tree val)
  {
    edge e;
+   unsigned i, n;
+   tree stmt;
  
!   stmt = last_stmt (bb);
!   if (TREE_CODE (stmt) != CF_EXPR)
!     abort ();
  
    if (TREE_CODE (val) != INTEGER_CST)
      return NULL;
  
!   if (simple_cst_equal (val, integer_zero_node))
      {
!       /* Find the edge with EDGE_ZERO_VALUE flag, if it is available.  */
!       for (e = bb->succ; e; e = e->succ_next)
! 	if (e->flags & EDGE_ZERO_VALUE)
! 	  return e;
!     }
  
!   n = CF_EXPR_N_ALTS (stmt);
!   for (i = 0; i < n; i++)
!     {
!       if (CF_EXPR_ALT_HIGH (stmt, i) == NULL)
  	{
  	  /* A `normal' case label.  */
! 	  if (simple_cst_equal (CF_EXPR_ALT_LOW (stmt, i), val) == 1)
! 	    return CF_EXPR_ALT_EDGE (stmt, i);
  	}
        else
  	{
  	  /* A case range.  We can only handle integer ranges.  */
! 	  if (tree_int_cst_compare (CF_EXPR_ALT_LOW (stmt, i), val) <= 0
! 	      && tree_int_cst_compare (CF_EXPR_ALT_HIGH (stmt, i), val) >= 0)
! 	    return CF_EXPR_ALT_EDGE (stmt, i);
  	}
      }
  
!   /* Find a default edge.  */
!   for (e = bb->succ; e; e = e->succ_next)
!     if (e->flags & EDGE_DEFAULT_VALUE)
!       return e;
! 
!   /* There always should be a taken edge.  */
!   abort ();
  }
  
  /* If all the phi nodes in DEST have alternatives for E1 and E2 and
*************** is_ctrl_stmt (tree t)
*** 2164,2170 ****
  	  || TREE_CODE (t) == SWITCH_EXPR
  	  || TREE_CODE (t) == GOTO_EXPR
  	  || TREE_CODE (t) == RETURN_EXPR
! 	  || TREE_CODE (t) == RESX_EXPR);
  }
  
  /* Return true if T is a stmt that may or may not alter the flow of control
--- 2079,2086 ----
  	  || TREE_CODE (t) == SWITCH_EXPR
  	  || TREE_CODE (t) == GOTO_EXPR
  	  || TREE_CODE (t) == RETURN_EXPR
! 	  || TREE_CODE (t) == RESX_EXPR
! 	  || TREE_CODE (t) == CF_EXPR);
  }
  
  /* Return true if T is a stmt that may or may not alter the flow of control
*************** stmt_ends_bb_p (tree t)
*** 2310,2315 ****
--- 2226,2365 ----
    return is_ctrl_stmt (t) || is_ctrl_altering_stmt (t);
  }
  
+ /* Replace the CF_EXPR pointed by BSI by a COND_EXPR or a SWITCH_EXPR.  */
+ static void
+ disband_cf_node (block_stmt_iterator bsi)
+ {
+   edge e, e_default, e_zero;
+   tree stmt = bsi_stmt (bsi);
+   basic_block bb = bb_for_stmt (stmt);
+ 
+   e_default = e_zero = NULL;
+   for (e = bb->succ; e; e = e->succ_next)
+     {
+       if (e->flags & EDGE_DEFAULT_VALUE)
+ 	e_default = e;
+       if (e->flags & EDGE_ZERO_VALUE)
+ 	e_zero = e;
+     }
+   if (!e_default)
+     abort ();
+ 	      
+   if (CF_EXPR_N_ALTS (stmt) == 0)
+     {
+       tree then_s, else_s;
+ 
+       /* Create a cond_expr.  */
+       if (!e_zero || e_zero == e_default)
+ 	abort ();
+ 
+       if (e_default->dest == bb->next_bb)
+ 	then_s = build_empty_stmt ();
+       else
+ 	then_s = build1 (GOTO_EXPR, void_type_node,
+ 			 tree_block_label (e_default->dest));
+       if (e_zero->dest == bb->next_bb)
+ 	else_s = build_empty_stmt ();
+       else
+ 	else_s = build1 (GOTO_EXPR, void_type_node,
+ 			 tree_block_label (e_zero->dest));
+ 
+       stmt = build (COND_EXPR, void_type_node, CF_EXPR_COND (stmt),
+ 		    then_s, else_s);
+     }
+   else
+     {
+       unsigned i, alt, n = CF_EXPR_N_ALTS (stmt) + (e_zero != 0) + 1;
+       tree vec = make_tree_vec (n);
+ 
+       TREE_VEC_ELT (vec, 0) = build (CASE_LABEL_EXPR, void_type_node,
+ 				     NULL_TREE, NULL_TREE,
+ 				     tree_block_label (e_default->dest));
+       if (e_zero)
+ 	{
+ 	  TREE_VEC_ELT (vec, 1) = build (CASE_LABEL_EXPR, void_type_node,
+ 					 integer_zero_node, NULL_TREE,
+ 					 tree_block_label (e_zero->dest));
+ 	  i = 2;
+ 	}
+       else
+ 	i = 1;
+ 
+       for (alt = 0; alt < CF_EXPR_N_ALTS (stmt); alt++, i++)
+ 	{
+ 	  e = CF_EXPR_ALT_EDGE (stmt, alt);
+ 	  TREE_VEC_ELT (vec, i) = build (CASE_LABEL_EXPR, void_type_node,
+ 					 CF_EXPR_ALT_LOW (stmt, alt),
+ 					 CF_EXPR_ALT_HIGH (stmt, alt),
+ 					 tree_block_label (e->dest));
+ 	}
+ 
+       /* Create a switch_expr.  */
+       stmt = build (SWITCH_EXPR, void_type_node, CF_EXPR_COND (stmt),
+ 		    NULL_TREE, vec);
+     }
+ 
+   bsi_replace (&bsi, stmt);
+ }
+ 
+ /* Make COND_EXPRs and SWITCH_EXPRs from the CF_EXPR nodes and add gotos
+    that were represented implicitly.  */
+ 
+ static void
+ disband_cf_nodes (void)
+ {
+   basic_block bb;
+   block_stmt_iterator last;
+   tree stmt;
+   edge e;
+ 
+   FOR_EACH_BB (bb)
+     {
+       last = bsi_last (bb);
+       if (!bsi_end_p (last))
+ 	stmt = bsi_stmt (last);
+       else
+ 	stmt = error_mark_node;
+ 
+       if (TREE_CODE (stmt) == CF_EXPR)
+ 	{
+ 	  disband_cf_node (last);
+ 	  continue;
+ 	}
+ 
+       /* If the last statement is a null return and we may fallthru to exit,
+          remove the return.  */
+       if (TREE_CODE (stmt) == RETURN_EXPR)
+ 	{
+ 	  if (TREE_OPERAND (stmt, 0)
+ 	      || bb->next_bb != EXIT_BLOCK_PTR)
+ 	    continue;
+ 
+ 	  if (bb->succ->succ_next)
+ 	    abort ();
+ 
+ 	  bsi_remove (&last);
+ 	  bb->succ->flags |= EDGE_FALLTHRU;
+ 	  continue;
+ 	}
+ 
+       /* Find a fallthru edge and emit the goto if neccesary.  */
+       for (e = bb->succ; e; e = e->succ_next)
+ 	if (e->flags & EDGE_FALLTHRU)
+ 	  break;
+       if (!e
+ 	  || e->dest == bb->next_bb)
+ 	continue;
+ 
+       if (e->dest == EXIT_BLOCK_PTR)
+ 	abort ();
+ 
+       bsi_insert_after (&last,
+ 			build1 (GOTO_EXPR, void_type_node,
+ 				tree_block_label (e->dest)),
+ 			BSI_NEW_STMT);
+     }
+ }
  
  /* Remove all the blocks and edges that make up the flowgraph.  */
  
*************** void
*** 2317,2323 ****
  delete_tree_cfg (void)
  {
    if (n_basic_blocks > 0)
!     free_blocks_annotations ();
    free_basic_block_vars (0);
    tree_bb_root = NULL;
  }
--- 2367,2377 ----
  delete_tree_cfg (void)
  {
    if (n_basic_blocks > 0)
!     {
!       disband_cf_nodes ();
!       free_blocks_annotations ();
!     }
! 
    free_basic_block_vars (0);
    tree_bb_root = NULL;
  }
*************** bsi_move_to_bb_end (block_stmt_iterator 
*** 2437,2442 ****
--- 2491,2499 ----
  void
  bsi_replace (const block_stmt_iterator *bsi, tree stmt)
  {
+   SET_EXPR_LOCUS (stmt, EXPR_LOCUS (bsi_stmt (*bsi)));
+   set_bb_for_stmt (stmt, bsi->bb);
+       
    *bsi_stmt_ptr (*bsi) = stmt;
    modify_stmt (stmt);
  }
*************** tree_find_edge_insert_loc (edge e, block
*** 2486,2492 ****
  	return false;
      }
  
!   /* If the source has one successor and the edge is not abnormal,
       insert there.  Except for the entry block.  */
    src = e->src;
    if ((e->flags & EDGE_ABNORMAL) == 0
--- 2543,2550 ----
  	return false;
      }
  
!   /* If the source has one successor and the last statement either does not end
!      the basic block or is a control one, and the edge is not abnormal,
       insert there.  Except for the entry block.  */
    src = e->src;
    if ((e->flags & EDGE_ABNORMAL) == 0
*************** tree_find_edge_insert_loc (edge e, block
*** 2497,2505 ****
        if (bsi_end_p (*bsi))
  	return true;
  
!       /* Make sure we insert before a final goto statement.  */
        tmp = bsi_stmt (*bsi);
!       return !is_ctrl_stmt (tmp);
      }
  
    /* Otherwise, create a new basic block, and split this edge.  */
--- 2555,2566 ----
        if (bsi_end_p (*bsi))
  	return true;
  
!       /* Make sure we insert before a final control statement.  */
        tmp = bsi_stmt (*bsi);
!       if (is_ctrl_stmt (tmp))
! 	return false;
!       else if (!stmt_ends_bb_p (tmp))
! 	return true;
      }
  
    /* Otherwise, create a new basic block, and split this edge.  */
*************** tree_split_edge (edge edge_in)
*** 2602,2667 ****
    /* Place the new block in the block list.  Try to keep the new block
       near its "logical" location.  This is of most help to humans looking
       at debugging dumps.  */
!   if (edge_in->flags & EDGE_FALLTHRU)
      after_bb = edge_in->src;
    else
      {
        edge e;
  
        for (e = dest->pred; e ; e = e->pred_next)
! 	if (e->flags & EDGE_FALLTHRU)
  	  break;
        if (!e)
  	after_bb = dest->prev_bb;
        else
! 	{
! 	  after_bb = EXIT_BLOCK_PTR->prev_bb;
! 	  for (e = after_bb->succ; e ; e = e->succ_next)
! 	    if (e->flags & EDGE_FALLTHRU)
! 	      break;
! 	  if (e)
! 	    {
! 	      block_stmt_iterator bsi;
! 	      tree x;
! 
! 	      /* We have a fallthru to exit out of the last block.
! 		 Transform this to a return statement.  */
! 	      /* ??? Can we have multiple outgoing edges here?  COND_EXPR
! 		 always has two gotos, and I can't think how one would have
! 		 achived this via EH.  */
! 	      if (e != after_bb->succ || e->succ_next)
! 		abort ();
! 	
! 	      x = build (RETURN_EXPR, void_type_node, NULL_TREE);
! 	      bsi = bsi_last (after_bb);
! 	      bsi_insert_after (&bsi, x, BSI_NEW_STMT);
! 
! 	      e->flags &= ~EDGE_FALLTHRU;
! 	    }
! 	}
      }
  
    new_bb = create_bb (NULL, after_bb);
    create_block_annotation (new_bb);
!   new_edge = make_edge (new_bb, dest, 0);
! 
!   if (edge_in->flags & EDGE_FALLTHRU)
!     {
!       new_edge->flags = EDGE_FALLTHRU;
!       redirect_edge_succ (edge_in, new_bb);
!     }
!   else
!     {
!       block_stmt_iterator i;
!       tree x;
! 
!       if (!tree_redirect_edge_and_branch_1 (edge_in, new_bb, true))
! 	abort ();
! 
!       x = build (GOTO_EXPR, void_type_node, tree_block_label (dest));
!       i = bsi_last (new_bb);
!       bsi_insert_after (&i, x, BSI_NEW_STMT);
!     }
  
    /* Find all the PHI arguments on the original edge, and change them to
       the new edge.  */
--- 2663,2687 ----
    /* Place the new block in the block list.  Try to keep the new block
       near its "logical" location.  This is of most help to humans looking
       at debugging dumps.  */
!   if (edge_in->src->next_bb == edge_in->dest)
      after_bb = edge_in->src;
    else
      {
        edge e;
  
        for (e = dest->pred; e ; e = e->pred_next)
! 	if (e->src->next_bb == dest)
  	  break;
        if (!e)
  	after_bb = dest->prev_bb;
        else
! 	after_bb = EXIT_BLOCK_PTR->prev_bb;
      }
  
    new_bb = create_bb (NULL, after_bb);
    create_block_annotation (new_bb);
!   redirect_edge_succ (edge_in, new_bb);
!   new_edge = make_edge (new_bb, dest, EDGE_FALLTHRU);
  
    /* Find all the PHI arguments on the original edge, and change them to
       the new edge.  */
*************** tree_split_edge (edge edge_in)
*** 2679,2702 ****
    return new_bb;
  }
  
- /* Return true when BB has label LABEL in it.  */
- static bool
- has_label_p (basic_block bb, tree label)
- {
-   block_stmt_iterator bsi;
- 
-   for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-     {
-       tree stmt = bsi_stmt (bsi);
- 
-       if (TREE_CODE (stmt) != LABEL_EXPR)
- 	return false;
-       if (LABEL_EXPR_LABEL (stmt) == label)
- 	return true;
-     }
-   return false;
- }
- 
  /* Verifies that the flow information is OK.  */
  
  static int
--- 2699,2704 ----
*************** tree_verify_flow_info (void)
*** 2706,2715 ****
    basic_block bb;
    block_stmt_iterator bsi;
    tree stmt;
  
    FOR_EACH_BB (bb)
      {
!       edge e;
        bool found_ctrl_stmt = false;
        tree phi;
        int i;
--- 2708,2725 ----
    basic_block bb;
    block_stmt_iterator bsi;
    tree stmt;
+   edge e;
+ 
+   for (e = EXIT_BLOCK_PTR->pred; e; e = e->pred_next)
+     if (e->flags & EDGE_FALLTHRU)
+       {
+ 	error ("Fallthru to exit from bb %d\n", e->src->index);
+ 	err = 1;
+       }
  
    FOR_EACH_BB (bb)
      {
!       edge f;
        bool found_ctrl_stmt = false;
        tree phi;
        int i;
*************** tree_verify_flow_info (void)
*** 2799,2902 ****
  	      err = 1;
  	    }
  	}
        bsi = bsi_last (bb);
        if (bsi_end_p (bsi))
  	continue;
  
        for (e = bb->succ; e; e = e->succ_next)
! 	if (e->flags & EDGE_FALLTHRU && e->dest != bb->next_bb)
  	  {
! 	    error ("Fallthru edge of bb %d does not point to following block\n", bb->index);
  	    err = 1;
  	  }
  
- 
        stmt = bsi_stmt (bsi);
        switch (TREE_CODE (stmt))
  	{
  	case COND_EXPR:
  	  {
! 	    edge true_edge;
! 	    edge false_edge;
! 	    if (TREE_CODE (COND_EXPR_THEN (stmt)) != GOTO_EXPR
! 		|| TREE_CODE (COND_EXPR_ELSE (stmt)) != GOTO_EXPR)
  	      {
! 		error ("Structured COND_EXPR at end of bb %d\n", bb->index);
! 		err = 1;
  	      }
! 	    if (bb->succ->flags & EDGE_TRUE_VALUE)
! 	      true_edge = bb->succ, false_edge = bb->succ->succ_next;
! 	    else
! 	      false_edge = bb->succ, true_edge = bb->succ->succ_next;
! 	    if (!true_edge || !false_edge
! 		|| !(true_edge->flags & EDGE_TRUE_VALUE)
! 		|| !(false_edge->flags & EDGE_FALSE_VALUE)
! 		|| (true_edge->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL))
! 		|| (false_edge->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL))
! 		|| bb->succ->succ_next->succ_next)
  	      {
! 		error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
! 		err = 1;
  	      }
! 	    if (!has_label_p (true_edge->dest,
! 			      GOTO_DESTINATION (COND_EXPR_THEN (stmt)))
! 		|| !has_label_p (false_edge->dest,
! 				 GOTO_DESTINATION (COND_EXPR_ELSE (stmt))))
  	      {
! 		error ("Label %s does not match edge at end of bb %d\n",
! 		       IDENTIFIER_POINTER (DECL_NAME (stmt)),
! 		       bb->index);
  		err = 1;
  	      }
  	  }
! 	  break;
  	case GOTO_EXPR:
  	  if (simple_goto_p (stmt))
! 	    {
! 	      if (!bb->succ || bb->succ->succ_next
! 		  || (bb->succ->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
! 					 | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
! 		{
! 		  error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
! 		  err = 1;
! 		}
! 	      if (!has_label_p (bb->succ->dest, GOTO_DESTINATION (stmt)))
! 		{
! 		  error ("Label %s does not match edge at end of bb %d\n",
! 			 IDENTIFIER_POINTER (DECL_NAME (stmt)),
! 			 bb->index);
! 		  err = 1;
! 		}
! 	    }
! 	  else
! 	    {
! 	      /* We shall double check that the labels in destination blocks have
! 	         address taken.  */
  
  	      for (e = bb->succ; e; e = e->succ_next)
! 		if ((e->flags & (EDGE_FALLTHRU | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE))
! 		    || !(e->flags & EDGE_ABNORMAL))
! 		  {
! 		    error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
! 		    err = 1;
! 		  }
! 	      if (nonlocal_goto_p (stmt))
  		{
! 	          for (e = bb->succ; e; e = e->succ_next)
! 		    if (e->dest == EXIT_BLOCK_PTR)
! 		      break;
! 		  if (!e)
! 		    {
! 		      error ("Missing edge to exit past nonlocal goto bb %d\n", bb->index);
! 		      err = 1;
! 		    }
  		}
  	    }
  	  break;
  	case RETURN_EXPR:
  	  if (!bb->succ || bb->succ->succ_next
  	      || (bb->succ->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
! 		  		     | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
  	    {
  	      error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
  	      err = 1;
--- 2809,2938 ----
  	      err = 1;
  	    }
  	}
+ 
        bsi = bsi_last (bb);
        if (bsi_end_p (bsi))
  	continue;
  
        for (e = bb->succ; e; e = e->succ_next)
! 	if ((e->flags & EDGE_FALLTHRU)
! 	    && is_ctrl_stmt (bsi_stmt (bsi)))
  	  {
! 	    error ("Fallthru edge after a control statement in bb %d \n",
! 		   bb->index);
  	    err = 1;
  	  }
  
        stmt = bsi_stmt (bsi);
        switch (TREE_CODE (stmt))
  	{
  	case COND_EXPR:
+ 	case SWITCH_EXPR:
+ 	  abort ();
+ 
+ 	case CF_EXPR:
  	  {
! 	    edge default_edge = NULL;
! 	    edge e;
! 	    unsigned i, n = CF_EXPR_N_ALTS (stmt);
! 
! 	    /* Mark all destination basic block.  */
! 	    for (i = 0; i < n; i++)
  	      {
! 		e = CF_EXPR_ALT_EDGE (stmt, i);
! 
! 		if (e != find_edge (e->src, e->dest))
! 		  {
! 		    error ("CF_EXPR contains outdated version of %d->%d edge\n",
! 			   bb->index, e->dest->index);
! 		    err = 1;
! 		  }
! 		  
! 		if (e->dest->aux && e->dest->aux != (void *)1)
! 		  abort ();
! 		e->dest->aux = (void *)1;
  	      }
! 
! 	    for (e = bb->succ; e; e = e->succ_next)
  	      {
! 		if (e->dest == EXIT_BLOCK_PTR)
! 		  {
! 		    error ("Control edge to exit in bb %d\n", bb->index);
! 		    err = 1;
! 		  }
! 
! 		if (e->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL))
! 		  {
! 		    error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
! 		    err = 1;
! 		  }
! 
! 		if (e->flags & EDGE_DEFAULT_VALUE)
! 		  default_edge = e;
! 
! 		if (!e->dest->aux
! 		    && !(e->flags & (EDGE_DEFAULT_VALUE | EDGE_ZERO_VALUE)))
! 		  {
! 		    error ("Extra outgoing edge %d->%d\n", bb->index, e->dest->index);
! 		    err = 1;
! 		  }
! 		e->dest->aux = (void *)2;
  	      }
! 
! 	    if (!default_edge)
  	      {
! 		error ("Missing default edge at bb %d\n", bb->index);
  		err = 1;
  	      }
+ 
+ 	    /* Check we do have all of them.  */
+ 	    for (i = 0; i < n; i++)
+ 	      {
+ 		e = CF_EXPR_ALT_EDGE (stmt, i);
+ 
+ 		if (e->dest->aux != (void *) 2)
+ 		  {
+ 		    error ("Missing edge %i->%i\n", bb->index, e->dest->index);
+ 		    err = 1;
+ 		  }
+ 	      }
+ 
+ 	    for (e = bb->succ; e; e = e->succ_next)
+ 	      e->dest->aux = (void *)0;
  	  }
! 	break;
! 
  	case GOTO_EXPR:
  	  if (simple_goto_p (stmt))
! 	    abort ();
! 	      
! 	  /* We shall double check that the labels in destination blocks have
! 	     address taken.  */
  
+ 	  for (e = bb->succ; e; e = e->succ_next)
+ 	    if ((e->flags & (EDGE_FALLTHRU | EDGE_DEFAULT_VALUE | EDGE_ZERO_VALUE))
+ 		|| !(e->flags & EDGE_ABNORMAL))
+ 	      {
+ 		error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
+ 		err = 1;
+ 	      }
+ 	  if (nonlocal_goto_p (stmt))
+ 	    {
  	      for (e = bb->succ; e; e = e->succ_next)
! 		if (e->dest == EXIT_BLOCK_PTR)
! 		  break;
! 	      if (!e)
  		{
! 		  error ("Missing edge to exit past nonlocal goto bb %d\n", bb->index);
! 		  err = 1;
  		}
  	    }
  	  break;
+ 
  	case RETURN_EXPR:
  	  if (!bb->succ || bb->succ->succ_next
  	      || (bb->succ->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
! 		  		     | EDGE_ZERO_VALUE | EDGE_DEFAULT_VALUE)))
  	    {
  	      error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
  	      err = 1;
*************** tree_verify_flow_info (void)
*** 2907,2963 ****
  	      err = 1;
  	    }
  	  break;
- 	case SWITCH_EXPR:
- 	  {
- 	    edge e;
- 	    size_t i, n;
- 	    tree vec;
- 
- 	    vec = SWITCH_LABELS (stmt);
- 	    n = TREE_VEC_LENGTH (vec);
- 
- 	    /* Mark all destination basic block.  */
- 	    for (i = 0; i < n; ++i)
- 	      {
- 		tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i));
- 		basic_block label_bb = label_to_block (lab);
- 
- 		if (label_bb->aux && label_bb->aux != (void *)1)
- 		  abort ();
- 		label_bb->aux = (void *)1;
- 	      }
  
! 	    for (e = bb->succ; e; e = e->succ_next)
! 	      {
! 		if (!e->dest->aux)
! 		  {
! 		    error ("Extra outgoing edge %d->%d\n", bb->index, e->dest->index);
! 		    err = 1;
! 		  }
! 		e->dest->aux = (void *)2;
! 		if ((e->flags & (EDGE_FALLTHRU | EDGE_ABNORMAL
! 					   | EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
! 		  {
! 		    error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
! 		    err = 1;
! 		  }
! 	      }
! 	    /* Check we do have all of them.  */
! 	    for (i = 0; i < n; ++i)
! 	      {
! 		tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i));
! 		basic_block label_bb = label_to_block (lab);
  
! 		if (label_bb->aux != (void *)2)
! 		  {
! 		    error ("Missing edge %i->%i\n", bb->index, label_bb->index);
! 		    err = 1;
! 		  }
! 	      }
! 	    for (e = bb->succ; e; e = e->succ_next)
! 	      e->dest->aux = (void *)0;
! 	  }
! 	default: ;
  	}
      }
  
--- 2943,2961 ----
  	      err = 1;
  	    }
  	  break;
  
! 	default:
! 	  f = NULL;
  
! 	  for (e = bb->succ; e; e = e->succ_next)
! 	    {
! 	      if (!(e->flags & (EDGE_ABNORMAL | EDGE_FALLTHRU))
! 		  || (e->flags & (EDGE_ZERO_VALUE | EDGE_DEFAULT_VALUE)))
! 		{
! 		  error ("Wrong outgoing edge flags at end of bb %d\n", bb->index);
! 		  err = 1;
! 		}
! 	    }
  	}
      }
  
*************** thread_jumps (void)
*** 3166,3172 ****
  {
    edge e, next, last, old;
    basic_block bb, dest, tmp;
!   tree phi, stmt;
    int arg;
    bool retval = false;
  
--- 3164,3170 ----
  {
    edge e, next, last, old;
    basic_block bb, dest, tmp;
!   tree phi;
    int arg;
    bool retval = false;
  
*************** thread_jumps (void)
*** 3183,3200 ****
        if (tree_forwarder_block_p (bb))
  	continue;
        
-       /* Due to limitations of ir, it is difficult to redirect edge except
- 	 in some simple cases.  Given that ir is slowly getting more sane,
- 	 don't invest too much energy into monsters of bsi_insert_on_edge
- 	 type.  */
-       stmt = last_stmt (bb);
-       if (stmt
- 	  && stmt_ends_bb_p (stmt)
- 	  && TREE_CODE (stmt) != GOTO_EXPR
- 	  && TREE_CODE (stmt) != COND_EXPR
- 	  && TREE_CODE (stmt) != SWITCH_EXPR)
- 	continue;
- 
        /* This block is now part of a forwarding path, mark it as not
  	 forwardable so that we can detect loops.   This bit will be
  	 reset below.  */
--- 3181,3186 ----
*************** tree_try_redirect_by_replacing_jump (edg
*** 3343,3363 ****
      return NULL;
    stmt = bsi_stmt (b);
  
!   if (TREE_CODE (stmt) == COND_EXPR
!       || TREE_CODE (stmt) == SWITCH_EXPR
!       || (TREE_CODE (stmt) == GOTO_EXPR && target == src->next_bb))
      {
!       if (target == src->next_bb)
! 	{
! 	  flags = EDGE_FALLTHRU;
!           bsi_remove (&b);
! 	}
!       else
! 	{
! 	  flags = 0;
!           stmt = build1 (GOTO_EXPR, void_type_node, tree_block_label (target));
!           bsi_replace (&b, stmt);
! 	}
        e = ssa_redirect_edge (e, target);
        e->flags = flags;
        return e;
--- 3329,3339 ----
      return NULL;
    stmt = bsi_stmt (b);
  
!   if (TREE_CODE (stmt) == CF_EXPR
!       || TREE_CODE (stmt) == GOTO_EXPR)
      {
!       flags = EDGE_FALLTHRU;
!       bsi_remove (&b);
        e = ssa_redirect_edge (e, target);
        e->flags = flags;
        return e;
*************** tree_try_redirect_by_replacing_jump (edg
*** 3370,3382 ****
     branch otherwise  */
  
  static edge
! tree_redirect_edge_and_branch_1 (edge e, basic_block dest, bool splitting)
  {
-   basic_block bb = e->src;
-   block_stmt_iterator bsi;
    edge ret;
!   tree label, stmt;
!   int flags;
  
    if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
      return NULL;
--- 3346,3356 ----
     branch otherwise  */
  
  static edge
! tree_redirect_edge_and_branch (edge e, basic_block dest)
  {
    edge ret;
!   tree last;
!   unsigned i, n;
  
    if (e->flags & (EDGE_ABNORMAL_CALL | EDGE_EH))
      return NULL;
*************** tree_redirect_edge_and_branch_1 (edge e,
*** 3388,3473 ****
    if (e->dest == dest)
      return NULL;
  
-   label = tree_block_label (dest);
- 
-   /* If our block does not end with a GOTO, then create one.
-      Otherwise redirect the existing GOTO_EXPR to LABEL.  */
- 
-   bsi = bsi_last (bb);
-   stmt = bsi_end_p (bsi) ? NULL : bsi_stmt (bsi);
-   flags = 0;
- 
-   switch (stmt ? TREE_CODE (stmt) : ERROR_MARK)
-     {
-     case COND_EXPR:
-       stmt = (e->flags & EDGE_TRUE_VALUE
- 	      ? COND_EXPR_THEN (stmt)
- 	      : COND_EXPR_ELSE (stmt));
-       flags = e->flags;
-       /* FALLTHRU */
- 
-     case GOTO_EXPR:
-       GOTO_DESTINATION (stmt) = label;
-       break;
- 
-     case SWITCH_EXPR:
-       {
- 	tree vec = SWITCH_LABELS (stmt);
- 	size_t i, n = TREE_VEC_LENGTH (vec);
- 
- 	for (i = 0; i < n; ++i)
- 	  {
- 	    tree elt = TREE_VEC_ELT (vec, i);
- 	    if (label_to_block (CASE_LABEL (elt)) == e->dest)
- 	      CASE_LABEL (elt) = label;
- 	  }
-       }
-       break;
- 
-     case CALL_EXPR:
-     case MODIFY_EXPR:
-       /* If this block ends with a statement that can alter control flow,
- 	 e.g. via throw or longjmp, then we can't just append to the 
- 	 current block.  We have to create a new block just to contain
- 	 the goto statement.  */
-       /* ??? In RTL equivalent we never create new basic blocks here.
- 	 Hopefully this will be just a temporary side case before we switch
- 	 to cfg_layout style mode with no explicit GOTO statements.  */
-       if (is_ctrl_altering_stmt (stmt))
- 	{
- 	  bb = tree_split_edge (e);
- 	  bsi = bsi_last (bb);
- 	  e = bb->succ;
- 	}
-       /* FALLTHRU */
- 
-     default:
-       /* Otherwise we can just append a goto to this block.  */
-       stmt = build1 (GOTO_EXPR, void_type_node, label);
-       bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
-       e->flags &= ~EDGE_FALLTHRU;
-       break;
-     }
- 
    /* Update/insert PHI nodes as necessary.  */
  
!   /* Now update the edges in the CFG.  When splitting edges, we do not 
!      want to remove PHI arguments.  */
!   if (splitting)
!     redirect_edge_succ (e, dest);
!   else
!     {
!       e = ssa_redirect_edge (e, dest);
!       e->flags |= flags;
!     }
  
!   return e;
! }
  
! static edge
! tree_redirect_edge_and_branch (edge e, basic_block dest)
! {
!   return tree_redirect_edge_and_branch_1 (e, dest, false);
  }
  
  /* Simple wrapper as we always can redirect fallthru edges.  */
--- 3362,3387 ----
    if (e->dest == dest)
      return NULL;
  
    /* Update/insert PHI nodes as necessary.  */
  
!   /* Now update the edges in the CFG.  */
!   ret = ssa_redirect_edge (e, dest);
  
!   if (e == ret)
!     return ret;
!       
!   last = last_stmt (e->src);
!   if (!last
!       || TREE_CODE (last) != CF_EXPR)
!     return ret;
  
!   /* Update the edge in CF_EXPR records.  */
!   n = CF_EXPR_N_ALTS (last);
!   for (i = 0; i < n; i++)
!     if (CF_EXPR_ALT_EDGE (last, i) == e)
!       CF_EXPR_ALT_EDGE (last, i) = ret;
! 
!   return ret;
  }
  
  /* Simple wrapper as we always can redirect fallthru edges.  */
*************** dump_function_to_file (tree fn, FILE *fi
*** 3517,3523 ****
  
    /* When gimple is lowered, the variables are no longer available in the
       bind_exprs, so display them separately.  */
!   if (cfun->unexpanded_var_list)
      {
        ignore_topmost_bind = true;
  
--- 3431,3437 ----
  
    /* When gimple is lowered, the variables are no longer available in the
       bind_exprs, so display them separately.  */
!   if (cfun && cfun->unexpanded_var_list)
      {
        ignore_topmost_bind = true;
  
*************** dump_function_to_file (tree fn, FILE *fi
*** 3546,3552 ****
  	{
  	  dump_generic_bb (file, bb, 2, flags);
  	}
! 	
        fprintf (file, "}\n");
      }
    else
--- 3460,3466 ----
  	{
  	  dump_generic_bb (file, bb, 2, flags);
  	}
! 
        fprintf (file, "}\n");
      }
    else
Index: tree-dfa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-dfa.c,v
retrieving revision 1.1.4.175
diff -c -3 -p -r1.1.4.175 tree-dfa.c
*** tree-dfa.c	21 Oct 2003 14:51:55 -0000	1.1.4.175
--- tree-dfa.c	14 Nov 2003 00:08:10 -0000
*************** get_stmt_operands (tree stmt)
*** 225,230 ****
--- 225,234 ----
        get_expr_operands (stmt, &SWITCH_COND (stmt), opf_none, prev_vops);
        break;
  
+     case CF_EXPR:
+       get_expr_operands (stmt, &CF_EXPR_COND (stmt), opf_none, prev_vops);
+       break;
+ 
      case ASM_EXPR:
        {
  	int noutputs = list_length (ASM_OUTPUTS (stmt));
Index: tree-flow.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-flow.h,v
retrieving revision 1.1.4.148
diff -c -3 -p -r1.1.4.148 tree-flow.h
*** tree-flow.h	13 Nov 2003 02:47:41 -0000	1.1.4.148
--- tree-flow.h	14 Nov 2003 00:08:10 -0000
*************** extern void cfg_remove_useless_stmts (vo
*** 439,446 ****
  extern basic_block tree_split_edge (edge);
  extern edge thread_edge (edge, basic_block);
  extern basic_block label_to_block (tree);
! extern bool cleanup_cond_expr_graph (basic_block, block_stmt_iterator);
! extern bool cleanup_switch_expr_graph (basic_block, block_stmt_iterator);
  extern void tree_optimize_tail_calls (void);
  extern basic_block tree_block_forwards_to (basic_block bb);
  extern void bsi_insert_on_edge (edge, tree);
--- 439,445 ----
  extern basic_block tree_split_edge (edge);
  extern edge thread_edge (edge, basic_block);
  extern basic_block label_to_block (tree);
! extern bool cleanup_cf_expr_graph (basic_block, block_stmt_iterator);
  extern void tree_optimize_tail_calls (void);
  extern basic_block tree_block_forwards_to (basic_block bb);
  extern void bsi_insert_on_edge (edge, tree);
*************** extern edge ssa_redirect_edge (edge, bas
*** 515,520 ****
--- 514,520 ----
  extern void set_is_used (tree);
  extern bool tree_ssa_useless_type_conversion (tree);
  extern void build_dominator_tree (dominance_info);
+ extern void delete_tree_ssa (tree);
  extern unsigned int next_ssa_version;
  
  /* In tree-ssa-pre.c  */
Index: tree-inline.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v
retrieving revision 1.26.2.61
diff -c -3 -p -r1.26.2.61 tree-inline.c
*** tree-inline.c	13 Nov 2003 20:51:11 -0000	1.26.2.61
--- tree-inline.c	14 Nov 2003 00:08:10 -0000
*************** walk_tree (tree *tp, walk_tree_fn func, 
*** 2006,2011 ****
--- 2006,2023 ----
  	case SAVE_EXPR:
  	  WALK_SUBTREE_TAIL (TREE_OPERAND (*tp, 0));
  
+ 	case CF_EXPR:
+ 	  {
+ 	    unsigned i, n = CF_EXPR_N_ALTS (*tp);
+ 
+ 	    for (i = 0; i < n; i++)
+ 	      {
+ 		WALK_SUBTREE (CF_EXPR_ALT_LOW (*tp, i));
+ 		WALK_SUBTREE (CF_EXPR_ALT_HIGH (*tp, i));
+ 	      }
+ 	    WALK_SUBTREE_TAIL (CF_EXPR_COND (*tp));
+ 	  }
+ 
  	case STATEMENT_LIST:
  	  {
  	    tree_stmt_iterator i;
Index: tree-optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-optimize.c,v
retrieving revision 1.1.4.71
diff -c -3 -p -r1.1.4.71 tree-optimize.c
*** tree-optimize.c	12 Nov 2003 22:06:26 -0000	1.1.4.71
--- tree-optimize.c	14 Nov 2003 00:08:10 -0000
*************** optimize_function_tree (tree fndecl, tre
*** 176,181 ****
--- 176,183 ----
        sbitmap_free (vars_to_rename);
      }
  
+   delete_tree_cfg ();
+ 
    /* Re-chain the statements from the blocks.  */
    {
      basic_block bb;
*************** optimize_function_tree (tree fndecl, tre
*** 184,191 ****
      FOR_EACH_BB (bb)
        append_to_statement_list_force (bb->stmt_list, chain);
    }
- 
-   delete_tree_cfg ();
  }
  
  
--- 186,191 ----
*************** tree_rest_of_compilation (tree fndecl, b
*** 313,322 ****
  
    /* Invoke the SSA tree optimizer.  */
    if (optimize >= 1 && !flag_disable_tree_ssa)
!     optimize_function_tree (fndecl, &chain);
  
!   DECL_SAVED_TREE (fndecl) = build (BIND_EXPR, void_type_node,
! 				    NULL_TREE, chain, NULL_TREE);
  
    /* If the function has a variably modified type, there may be
       SAVE_EXPRs in the parameter types.  Their context must be set to
--- 313,329 ----
  
    /* Invoke the SSA tree optimizer.  */
    if (optimize >= 1 && !flag_disable_tree_ssa)
!     {
!       optimize_function_tree (fndecl, &chain);
  
!       DECL_SAVED_TREE (fndecl) = build (BIND_EXPR, void_type_node,
! 					NULL_TREE, chain, NULL_TREE);
!       delete_tree_ssa (fndecl);
!       dump_function (TDI_optimized, fndecl);
!     }
!   else
!     DECL_SAVED_TREE (fndecl) = build (BIND_EXPR, void_type_node,
! 				      NULL_TREE, chain, NULL_TREE);
  
    /* If the function has a variably modified type, there may be
       SAVE_EXPRs in the parameter types.  Their context must be set to
Index: tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-pretty-print.c,v
retrieving revision 1.1.2.58
diff -c -3 -p -r1.1.2.58 tree-pretty-print.c
*** tree-pretty-print.c	12 Nov 2003 22:06:26 -0000	1.1.2.58
--- tree-pretty-print.c	14 Nov 2003 00:08:10 -0000
*************** dump_generic_node (pretty_printer *buffe
*** 731,737 ****
  	    else
  	      first = false;
  	    dump_generic_node (buffer, tsi_stmt (si), spc, flags, true);
- 	    pp_character (buffer, ';');
  	  }
        }
        break;
--- 731,736 ----
*************** dump_generic_node (pretty_printer *buffe
*** 752,757 ****
--- 751,765 ----
        pp_character (buffer, ')');
        break;
  
+     case CF_EXPR:
+       if (CF_EXPR_N_ALTS (node) == 0)
+ 	pp_string (buffer, "if (");
+       else
+ 	pp_string (buffer, "switch (");
+       dump_generic_node (buffer, CF_EXPR_COND (node), spc, flags, false);
+       pp_character (buffer, ')');
+       break;
+ 
      case COND_EXPR:
        if (TREE_TYPE (node) == void_type_node)
  	{
*************** dump_generic_node (pretty_printer *buffe
*** 1279,1284 ****
--- 1287,1293 ----
  		  dump_generic_node (buffer, elt, spc+4, flags, false);
  		  pp_string (buffer, " goto ");
  		  dump_generic_node (buffer, CASE_LABEL (elt), spc+4, flags, true);
+ 		  pp_semicolon (buffer);
  		}
  	    }
  	  newline_and_indent (buffer, spc+2);
*************** dump_phi_nodes (pretty_printer *buffer, 
*** 2147,2152 ****
--- 2156,2283 ----
      }
  }
  
+ /* Dump jump to basic block BB that is represented implicitly in the cfg
+    to BUFFER.  */
+ 
+ static void
+ pp_cfg_jump (pretty_printer *buffer, basic_block bb)
+ {
+   pp_string (buffer, "goto <bb ");
+   pp_decimal_int (buffer, bb->index);
+   pp_string (buffer, ">;");
+ }
+ 
+ /* Dump edges represented implicitly in basic block BB to BUFFER, indented
+    by INDENT spaces, with details given by FLAGS.  */
+ 
+ static void
+ dump_implicit_edges (pretty_printer *buffer, basic_block bb, int indent, int flags)
+ {
+   tree stmt;
+   edge e;
+ 
+   /* If the bb ends by a CF_EXPR node, we must provide the information that is
+      only available in the cfg.  */
+   stmt = last_stmt (bb);
+   if (stmt && TREE_CODE (stmt) == CF_EXPR)
+     {
+       edge e_default = NULL, e_zero = NULL;
+       unsigned i, n;
+ 
+       for (e = bb->succ; e; e = e->succ_next)
+ 	{
+ 	  if (e->flags & EDGE_DEFAULT_VALUE)
+ 	    e_default = e;
+ 	  if (e->flags & EDGE_ZERO_VALUE)
+ 	    e_zero = e;
+ 	}
+ 
+       n = CF_EXPR_N_ALTS (stmt);
+       if (n == 0)
+ 	{
+ 	  /* COND_EXPR like.  */
+ 	  INDENT (indent + 2);
+ 	  if (e_default)
+ 	    pp_cfg_jump (buffer, e_default->dest);
+ 	  else
+ 	    pp_semicolon (buffer);
+ 	  pp_newline (buffer);
+ 
+ 	  if (e_zero)
+ 	    {
+ 	      INDENT (indent);
+ 	      pp_string (buffer, "else");
+ 	      newline_and_indent (buffer, indent + 2);
+ 	      pp_cfg_jump (buffer, e_zero->dest);
+ 	      pp_newline (buffer);
+ 	    }
+ 	}
+       else
+ 	{
+ 	  /* SWITCH_EXPR like.  */
+ 	  INDENT (indent + 2);
+ 	  pp_character (buffer, '{');
+ 	  newline_and_indent (buffer, indent + 2);
+ 
+ 	  if (e_zero)
+ 	    {
+ 	      pp_string (buffer, "case 0:");
+ 	      newline_and_indent (buffer, indent + 4);
+ 	      pp_cfg_jump (buffer, e_zero->dest);
+ 	      newline_and_indent (buffer, indent + 2);
+ 	    }
+ 
+ 	  for (i = 0; i < n; i++)
+ 	    {
+ 	      tree low = CF_EXPR_ALT_LOW (stmt, i);
+ 	      tree high = CF_EXPR_ALT_HIGH (stmt, i);
+ 
+ 	      if (high)
+ 		{
+ 		  pp_string (buffer, "case ");
+ 		  dump_generic_node (buffer, low, indent + 2, flags, false);
+ 		  pp_string (buffer, " ... ");
+ 		  dump_generic_node (buffer, high, indent + 2, flags, false);
+ 		}
+ 	      else
+ 		{
+ 		  pp_string (buffer, "case ");
+ 		  dump_generic_node (buffer, low, indent + 2, flags, false);
+ 		}
+ 	      pp_colon (buffer);
+ 	      newline_and_indent (buffer, indent + 4);
+ 	      pp_cfg_jump (buffer, CF_EXPR_ALT_EDGE (stmt, i)->dest);
+ 	      newline_and_indent (buffer, indent + 2);
+ 	    }
+ 
+ 	  if (e_default)
+ 	    {
+ 	      pp_string (buffer, "default:");
+ 	      newline_and_indent (buffer, indent + 4);
+ 	      pp_cfg_jump (buffer, e_default->dest);
+ 	      newline_and_indent (buffer, indent + 2);
+ 	    }
+ 
+ 	  pp_character (buffer, '}');
+ 	  pp_newline (buffer);
+ 	}
+ 
+       return;
+     }
+   
+   /* If there is a fallthru edge, we may need to add an artificial goto to the
+      dump.  */
+   for (e = bb->succ; e; e = e->succ_next)
+     if (e->flags & EDGE_FALLTHRU)
+       break;
+   if (e && e->dest != bb->next_bb)
+     {
+       INDENT (indent);
+       pp_cfg_jump (buffer, e->dest);
+       pp_newline (buffer);
+     }
+ }
+ 
  /* Dumps basic block BB to buffer BUFFER with details described by FLAGS and
     indented by INDENT spaces.  */
  
*************** dump_generic_bb_buff (pretty_printer *bu
*** 2179,2184 ****
--- 2310,2317 ----
        dump_generic_node (buffer, stmt, curr_indent, flags, true);
        pp_newline (buffer);
      }
+ 
+   dump_implicit_edges (buffer, bb, indent, flags);
  
    if (flags & TDF_BLOCKS)
      dump_bb_end (buffer, bb, indent);
Index: tree-simple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-simple.c,v
retrieving revision 1.1.4.60
diff -c -3 -p -r1.1.4.60 tree-simple.c
*** tree-simple.c	12 Nov 2003 22:06:26 -0000	1.1.4.60
--- tree-simple.c	14 Nov 2003 00:08:10 -0000
*************** is_gimple_stmt (tree t)
*** 325,330 ****
--- 325,331 ----
        /* These are only valid if they're void.  */
        return VOID_TYPE_P (TREE_TYPE (t));
  
+     case CF_EXPR:
      case SWITCH_EXPR:
      case GOTO_EXPR:
      case RETURN_EXPR:
Index: tree-ssa-ccp.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-ccp.c,v
retrieving revision 1.1.2.110
diff -c -3 -p -r1.1.2.110 tree-ssa-ccp.c
*** tree-ssa-ccp.c	13 Nov 2003 02:38:01 -0000	1.1.2.110
--- tree-ssa-ccp.c	14 Nov 2003 00:08:10 -0000
*************** visit_stmt (tree stmt)
*** 597,603 ****
  
    /* If STMT is a conditional branch, see if we can determine which branch
       will be taken.  */
!   else if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR)
      visit_cond_stmt (stmt);
  
    /* Any other kind of statement is not interesting for constant
--- 597,603 ----
  
    /* If STMT is a conditional branch, see if we can determine which branch
       will be taken.  */
!   else if (TREE_CODE (stmt) == CF_EXPR)
      visit_cond_stmt (stmt);
  
    /* Any other kind of statement is not interesting for constant
*************** get_rhs (tree stmt)
*** 1701,1710 ****
  
    if (code == MODIFY_EXPR)
      return TREE_OPERAND (stmt, 1);
!   if (code == COND_EXPR)
!     return COND_EXPR_COND (stmt);
!   else if (code == SWITCH_EXPR)
!     return SWITCH_COND (stmt);
    else if (code == RETURN_EXPR)
      {
        if (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR)
--- 1701,1708 ----
  
    if (code == MODIFY_EXPR)
      return TREE_OPERAND (stmt, 1);
!   if (code == CF_EXPR)
!     return CF_EXPR_COND (stmt);
    else if (code == RETURN_EXPR)
      {
        if (TREE_CODE (TREE_OPERAND (stmt, 0)) == MODIFY_EXPR)
*************** set_rhs (tree *stmt_p, tree expr)
*** 1731,1740 ****
  
    if (code == MODIFY_EXPR)
      TREE_OPERAND (stmt, 1) = expr;
!   else if (code == COND_EXPR)
!     COND_EXPR_COND (stmt) = expr;
!   else if (code == SWITCH_EXPR)
!     SWITCH_COND (stmt) = expr;
    else if (code == RETURN_EXPR)
      {
        if (TREE_OPERAND (stmt, 0)
--- 1729,1736 ----
  
    if (code == MODIFY_EXPR)
      TREE_OPERAND (stmt, 1) = expr;
!   else if (code == CF_EXPR)
!     CF_EXPR_COND (stmt) = expr;
    else if (code == RETURN_EXPR)
      {
        if (TREE_OPERAND (stmt, 0)
Index: tree-ssa-dce.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-dce.c,v
retrieving revision 1.1.2.68
diff -c -3 -p -r1.1.2.68 tree-ssa-dce.c
*** tree-ssa-dce.c	13 Nov 2003 02:47:41 -0000	1.1.2.68
--- tree-ssa-dce.c	14 Nov 2003 00:08:10 -0000
*************** stmt_useful_p (tree stmt)
*** 276,288 ****
  	return true;
        break;
  
-     case COND_EXPR:
-       /* Check if the dest labels are the same. If they are, the condition
- 	 is useless.  */
-       if (GOTO_DESTINATION (COND_EXPR_THEN (stmt))
- 	  == GOTO_DESTINATION (COND_EXPR_ELSE (stmt)))
- 	return false;
- 
      default:
        break;
      }
--- 276,281 ----
Index: tree-ssa-dom.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa-dom.c,v
retrieving revision 1.1.2.77
diff -c -3 -p -r1.1.2.77 tree-ssa-dom.c
*** tree-ssa-dom.c	11 Nov 2003 18:04:46 -0000	1.1.2.77
--- tree-ssa-dom.c	14 Nov 2003 00:08:10 -0000
*************** tree_ssa_dominator_optimize_1 (tree fnde
*** 359,365 ****
        break;
  
    /* Reset block_forwardable in each block's annotation.  We use that
!      attribute when threading through COND_EXPRs.  */
    FOR_EACH_BB (bb)
      bb_ann (bb)->forwardable = 1;
  
--- 359,365 ----
        break;
  
    /* Reset block_forwardable in each block's annotation.  We use that
!      attribute when threading through CF_EXPRs.  */
    FOR_EACH_BB (bb)
      bb_ann (bb)->forwardable = 1;
  
*************** thread_across_edge (edge e, varray_type 
*** 504,512 ****
  		 || TREE_CODE (stmt) == LABEL_EXPR))
  	bsi_next (&bsi);
  
!       /* 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;
  	  unsigned int i;
--- 504,512 ----
  		 || TREE_CODE (stmt) == LABEL_EXPR))
  	bsi_next (&bsi);
  
!       /* If we stopped at a CF_EXPR, then see if we know which arm will
  	 be taken.  */
!       if (stmt && TREE_CODE (stmt) == CF_EXPR)
  	{
  	  tree cached_lhs;
  	  unsigned int i;
*************** dom_opt_finalize_block (struct dom_walk_
*** 644,661 ****
        thread_across_edge (bb->succ, NULL);
      }
    else if ((last = last_stmt (bb))
! 	   && TREE_CODE (last) == COND_EXPR
! 	   && TREE_CODE_CLASS (TREE_CODE (COND_EXPR_COND (last))) == '<'
  	   && bb->succ
- 	   && (bb->succ->flags & EDGE_ABNORMAL) == 0
  	   && bb->succ->succ_next
- 	   && (bb->succ->succ_next->flags & EDGE_ABNORMAL) == 0
  	   && ! bb->succ->succ_next->succ_next)
      {
        edge e = bb->succ;
        edge true_edge, false_edge;
  
!       if (e->flags & EDGE_TRUE_VALUE)
  	{
  	  true_edge = e;
  	  false_edge = e->succ_next;
--- 644,659 ----
        thread_across_edge (bb->succ, NULL);
      }
    else if ((last = last_stmt (bb))
! 	   && TREE_CODE (last) == CF_EXPR
! 	   && TREE_CODE_CLASS (TREE_CODE (CF_EXPR_COND (last))) == '<'
  	   && bb->succ
  	   && bb->succ->succ_next
  	   && ! bb->succ->succ_next->succ_next)
      {
        edge e = bb->succ;
        edge true_edge, false_edge;
  
!       if (e->flags & EDGE_DEFAULT_VALUE)
  	{
  	  true_edge = e;
  	  false_edge = e->succ_next;
*************** dom_opt_finalize_block (struct dom_walk_
*** 666,678 ****
  	  true_edge = e->succ_next;
  	}
  
        /* If the THEN arm is the end of a dominator tree, then try to thread
  	 through its edge.  */
        if (! dom_children (bb)
  	  || ! bitmap_bit_p (dom_children (bb), true_edge->dest->index))
  	{
  	  unsigned limit = VARRAY_ACTIVE_SIZE (bd->avail_exprs);
! 	  record_cond_is_true (COND_EXPR_COND (last), &bd->avail_exprs);
  	  thread_across_edge (true_edge, NULL);
  	  if (limit != VARRAY_ACTIVE_SIZE (bd->avail_exprs))
  	    {
--- 664,680 ----
  	  true_edge = e->succ_next;
  	}
  
+       if (!(true_edge->flags & EDGE_DEFAULT_VALUE)
+ 	  || !(false_edge->flags & EDGE_ZERO_VALUE))
+ 	abort ();
+ 
        /* If the THEN arm is the end of a dominator tree, then try to thread
  	 through its edge.  */
        if (! dom_children (bb)
  	  || ! bitmap_bit_p (dom_children (bb), true_edge->dest->index))
  	{
  	  unsigned limit = VARRAY_ACTIVE_SIZE (bd->avail_exprs);
! 	  record_cond_is_true (CF_EXPR_COND (last), &bd->avail_exprs);
  	  thread_across_edge (true_edge, NULL);
  	  if (limit != VARRAY_ACTIVE_SIZE (bd->avail_exprs))
  	    {
*************** dom_opt_finalize_block (struct dom_walk_
*** 686,692 ****
  	  || ! bitmap_bit_p (dom_children (bb), false_edge->dest->index))
  	{
  	  unsigned limit = VARRAY_ACTIVE_SIZE (bd->avail_exprs);
! 	  record_cond_is_false (COND_EXPR_COND (last), &bd->avail_exprs);
  	  thread_across_edge (false_edge, NULL);
  	  if (limit != VARRAY_ACTIVE_SIZE (bd->avail_exprs))
  	    {
--- 688,694 ----
  	  || ! bitmap_bit_p (dom_children (bb), false_edge->dest->index))
  	{
  	  unsigned limit = VARRAY_ACTIVE_SIZE (bd->avail_exprs);
! 	  record_cond_is_false (CF_EXPR_COND (last), &bd->avail_exprs);
  	  thread_across_edge (false_edge, NULL);
  	  if (limit != VARRAY_ACTIVE_SIZE (bd->avail_exprs))
  	    {
*************** record_equivalences_from_incoming_edge (
*** 845,856 ****
        parent_block_last_stmt = NULL;
      }
  
!   /* If our parent block ended in a COND_EXPR, add any equivalences
!      created by the COND_EXPR to the hash table and initialize
       EQ_EXPR_VALUE appropriately.
  
       EQ_EXPR_VALUE is an assignment expression created when BB's immediate
!      dominator ends in a COND_EXPR statement whose predicate is of the form
       'VAR == VALUE', where VALUE may be another variable or a constant.
       This is used to propagate VALUE on the THEN_CLAUSE of that
       conditional. This assignment is inserted in CONST_AND_COPIES so that
--- 847,858 ----
        parent_block_last_stmt = NULL;
      }
  
!   /* If our parent block ended in a CF_EXPR, add any equivalences
!      created by the CF_EXPR to the hash table and initialize
       EQ_EXPR_VALUE appropriately.
  
       EQ_EXPR_VALUE is an assignment expression created when BB's immediate
!      dominator ends in a CF_EXPR statement whose predicate is of the form
       'VAR == VALUE', where VALUE may be another variable or a constant.
       This is used to propagate VALUE on the THEN_CLAUSE of that
       conditional. This assignment is inserted in CONST_AND_COPIES so that
*************** record_equivalences_from_incoming_edge (
*** 858,920 ****
       opportunities.  */
    if (parent_block_last_stmt
        && bb->pred->pred_next == NULL
!       && TREE_CODE (parent_block_last_stmt) == COND_EXPR
!       && (edge_flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE)))
!     eq_expr_value = get_eq_expr_value (parent_block_last_stmt,
! 				       (edge_flags & EDGE_TRUE_VALUE) != 0,
! 				       block_avail_exprs_p,
! 				       bb,
! 				       vrp_variables_p);
!   /* Similarly when the parent block ended in a SWITCH_EXPR.  */
!   else if (parent_block_last_stmt
! 	   && bb->pred->pred_next == NULL
! 	   && TREE_CODE (parent_block_last_stmt) == SWITCH_EXPR)
      {
!       tree switch_cond = SWITCH_COND (parent_block_last_stmt);
! 
!       /* Strip away any useless type conversions.  */
!       while (tree_ssa_useless_type_conversion (switch_cond))
! 	switch_cond = TREE_OPERAND (switch_cond, 0);
! 
!       /* If the switch's condition is an SSA variable, then we may
! 	 know its value at each of the case labels.  */
!       if (TREE_CODE (switch_cond) == SSA_NAME)
! 	{
! 	  tree switch_vec = SWITCH_LABELS (parent_block_last_stmt);
! 	  size_t i, n = TREE_VEC_LENGTH (switch_vec);
! 	  int case_count = 0;
! 	  tree match_case = NULL_TREE;
! 
! 	  /* Search the case labels for those whose destination is
! 	     the current basic block.  */
! 	  for (i = 0; i < n; ++i)
! 	    {
! 	      tree elt = TREE_VEC_ELT (switch_vec, i);
! 	      if (label_to_block (CASE_LABEL (elt)) == bb)
! 		{
! 		  if (++case_count > 1)
! 		    break;
! 		  match_case = elt;
! 		}
! 	    }
! 
! 	  /* If we encountered precisely one CASE_LABEL_EXPR and it
! 	     was not the default case, or a case range, then we know
! 	     the exact value of SWITCH_COND which caused us to get to
! 	     this block.  Record that equivalence in EQ_EXPR_VALUE.  */
! 	  if (case_count == 1
! 	      && CASE_LOW (match_case)
! 	      && !CASE_HIGH (match_case))
! 	    {
! 	      eq_expr_value = build (MODIFY_EXPR, TREE_TYPE (switch_cond),
! 				     switch_cond, CASE_LOW (match_case));
  	    }
  	}
      }
  
    /* If EQ_EXPR_VALUE (VAR == VALUE) is given, register the VALUE as a
       new value for VAR, so that occurrences of VAR can be replaced with
!      VALUE while re-writing the THEN arm of a COND_EXPR.  */
    if (eq_expr_value)
      {
        tree dest = TREE_OPERAND (eq_expr_value, 0);
--- 860,921 ----
       opportunities.  */
    if (parent_block_last_stmt
        && bb->pred->pred_next == NULL
!       && TREE_CODE (parent_block_last_stmt) == CF_EXPR)
      {
!       /* Equivalent of a COND_EXPR.  */
!       if (CF_EXPR_N_ALTS (parent_block_last_stmt) == 0)
! 	eq_expr_value = get_eq_expr_value (parent_block_last_stmt,
! 					   (edge_flags & EDGE_ZERO_VALUE) == 0,
! 					   block_avail_exprs_p,
! 					   bb,
! 					   vrp_variables_p);
!       else if (!(bb->pred->flags & EDGE_DEFAULT_VALUE))
! 	{
! 	  tree switch_cond = CF_EXPR_COND (parent_block_last_stmt);
! 
! 	  /* Strip away any useless type conversions.  */
! 	  while (tree_ssa_useless_type_conversion (switch_cond))
! 	    switch_cond = TREE_OPERAND (switch_cond, 0);
! 
! 	  /* If the switch's condition is an SSA variable, then we may
! 	     know its value at each of the case labels.  */
! 	  if (TREE_CODE (switch_cond) == SSA_NAME)
! 	    {
! 	      unsigned i, n = CF_EXPR_N_ALTS (parent_block_last_stmt);
! 	      tree match = NULL_TREE;
! 
! 	      if (bb->pred->flags & EDGE_ZERO_VALUE)
! 		match = integer_zero_node;
! 
! 	      /* Search the case labels for those whose destination is
! 		 the current basic block.  */
! 	      for (i = 0; i < n; i++)
! 		if (CF_EXPR_ALT_EDGE (parent_block_last_stmt, i)->dest == bb)
! 		  {
! 		    if (match
! 			|| CF_EXPR_ALT_HIGH (parent_block_last_stmt, i))
! 		      {
! 			match = NULL_TREE;
! 			break;
! 		      }
! 
! 		    match = CF_EXPR_ALT_LOW (parent_block_last_stmt, i);
! 		  }
! 
! 	      /* If we encountered precisely one CASE_LABEL_EXPR and it
! 		 was not the default case, or a case range, then we know
! 		 the exact value of SWITCH_COND which caused us to get to
! 		 this block.  Record that equivalence in EQ_EXPR_VALUE.  */
! 	      if (match)
! 		eq_expr_value = build (MODIFY_EXPR, TREE_TYPE (switch_cond),
! 				       switch_cond, match);
  	    }
  	}
      }
  
    /* If EQ_EXPR_VALUE (VAR == VALUE) is given, register the VALUE as a
       new value for VAR, so that occurrences of VAR can be replaced with
!      VALUE.  */
    if (eq_expr_value)
      {
        tree dest = TREE_OPERAND (eq_expr_value, 0);
*************** thread_jumps_walk_stmts (struct dom_walk
*** 1006,1014 ****
  
        /* First try to eliminate any conditionals which have a known
  	 compile time constant value.  */
!       if (TREE_CODE (stmt) == COND_EXPR || TREE_CODE (stmt) == SWITCH_EXPR)
  	cached_lhs = lookup_avail_expr (stmt, NULL, false);
!       if (! cached_lhs && TREE_CODE (stmt) == COND_EXPR)
  	cached_lhs = simplify_cond_and_lookup_avail_expr (stmt,
  							  NULL,
  							  stmt_ann (stmt),
--- 1007,1015 ----
  
        /* First try to eliminate any conditionals which have a known
  	 compile time constant value.  */
!       if (TREE_CODE (stmt) == CF_EXPR)
  	cached_lhs = lookup_avail_expr (stmt, NULL, false);
!       if (! cached_lhs && TREE_CODE (stmt) == CF_EXPR)
  	cached_lhs = simplify_cond_and_lookup_avail_expr (stmt,
  							  NULL,
  							  stmt_ann (stmt),
*************** thread_jumps_walk_stmts (struct dom_walk
*** 1018,1032 ****
  	{
  	  modify_stmt (stmt);
  
! 	  if (TREE_CODE (stmt) == COND_EXPR)
! 	    {
! 	      COND_EXPR_COND (stmt) = cached_lhs;
! 	      cfg_altered = cleanup_cond_expr_graph (bb, si);
! 	    }
! 	  else if (TREE_CODE (stmt) == SWITCH_EXPR)
  	    {
! 	      SWITCH_COND (stmt) = cached_lhs;
! 	      cfg_altered = cleanup_switch_expr_graph (bb, si);
  	    }
  
  	  continue;
--- 1019,1028 ----
  	{
  	  modify_stmt (stmt);
  
! 	  if (TREE_CODE (stmt) == CF_EXPR)
  	    {
! 	      CF_EXPR_COND (stmt) = cached_lhs;
! 	      cfg_altered = cleanup_cf_expr_graph (bb, si);
  	    }
  
  	  continue;
*************** thread_jumps_walk_stmts (struct dom_walk
*** 1034,1040 ****
  
        /* This is a simpler test than the one in optimize_stmt because
  	 we only care about recording equivalences for assignments.
!          RETURN_EXPRs, COND_EXPRs, and SWITCH_EXPRs can be ignored.  */
        may_optimize_p = (!stmt_ann (stmt)->has_volatile_ops
  			&& TREE_CODE (stmt) == MODIFY_EXPR
  			&& ! TREE_SIDE_EFFECTS (TREE_OPERAND (stmt, 1)));
--- 1030,1036 ----
  
        /* This is a simpler test than the one in optimize_stmt because
  	 we only care about recording equivalences for assignments.
!          RETURN_EXPRs and CF_EXPRs can be ignored.  */
        may_optimize_p = (!stmt_ann (stmt)->has_volatile_ops
  			&& TREE_CODE (stmt) == MODIFY_EXPR
  			&& ! TREE_SIDE_EFFECTS (TREE_OPERAND (stmt, 1)));
*************** simplify_rhs_and_lookup_avail_expr (tree
*** 1242,1248 ****
        tree op = TREE_OPERAND (rhs, 0);
  
        cond = build (GT_EXPR, boolean_type_node, op, integer_zero_node);
!       cond = build (COND_EXPR, void_type_node, cond, NULL, NULL);
        val = simplify_cond_and_lookup_avail_expr (cond, block_avail_exprs_p,
  						 NULL, false);
  
--- 1238,1244 ----
        tree op = TREE_OPERAND (rhs, 0);
  
        cond = build (GT_EXPR, boolean_type_node, op, integer_zero_node);
!       cond = make_cf_expr (cond, 0);
        val = simplify_cond_and_lookup_avail_expr (cond, block_avail_exprs_p,
  						 NULL, false);
  
*************** simplify_rhs_and_lookup_avail_expr (tree
*** 1276,1282 ****
  
        cond = build (LT_EXPR, boolean_type_node, op,
  		    convert (type, integer_zero_node));
!       cond = build (COND_EXPR, void_type_node, cond, NULL, NULL);
        val = simplify_cond_and_lookup_avail_expr (cond, block_avail_exprs_p,
  						 NULL, false);
  
--- 1272,1278 ----
  
        cond = build (LT_EXPR, boolean_type_node, op,
  		    convert (type, integer_zero_node));
!       cond = make_cf_expr (cond, 0);
        val = simplify_cond_and_lookup_avail_expr (cond, block_avail_exprs_p,
  						 NULL, false);
  
*************** find_equivalent_equality_comparison (tre
*** 1372,1379 ****
    return NULL;
  }
  
! /* STMT is a COND_EXPR for which we could not trivially determine its
!    result.  This routine attempts to find equivalent forms of the
     condition which we may be able to optimize better.  It also 
     uses simple value range propagation to optimize conditionals.  */
  
--- 1368,1375 ----
    return NULL;
  }
  
! /* STMT is a CF_EXPR for which we could not trivially determine
!    its value.  This routine attempts to find equivalent forms of the
     condition which we may be able to optimize better.  It also 
     uses simple value range propagation to optimize conditionals.  */
  
*************** simplify_cond_and_lookup_avail_expr (tre
*** 1383,1389 ****
  				     stmt_ann_t ann,
  				     int insert)
  {
!   tree cond = COND_EXPR_COND (stmt);
  
    if (TREE_CODE_CLASS (TREE_CODE (cond)) == '<')
      {
--- 1379,1385 ----
  				     stmt_ann_t ann,
  				     int insert)
  {
!   tree cond = CF_EXPR_COND (stmt);
  
    if (TREE_CODE_CLASS (TREE_CODE (cond)) == '<')
      {
*************** simplify_cond_and_lookup_avail_expr (tre
*** 1410,1416 ****
  		{
  		  /* Update the statement to use the new equivalent
  		     condition.  */
! 		  COND_EXPR_COND (stmt) = new_cond;
  		  ann->modified = 1;
  
  		  /* Lookup the condition and return its known value if it
--- 1406,1412 ----
  		{
  		  /* Update the statement to use the new equivalent
  		     condition.  */
! 		  CF_EXPR_COND (stmt) = new_cond;
  		  ann->modified = 1;
  
  		  /* Lookup the condition and return its known value if it
*************** eliminate_redundant_computations (tree s
*** 1839,1861 ****
  						     block_avail_exprs_p,
  						     ann,
  						     insert);
!   /* Similarly if this is a COND_EXPR and we did not find its
       expression in the hash table, simplify the condition and
       try again.  */
!   else if (! cached_lhs && TREE_CODE (stmt) == COND_EXPR)
      cached_lhs = simplify_cond_and_lookup_avail_expr (stmt,
  						      block_avail_exprs_p,
  						      ann,
  						      insert);
-   /* We could do the same with SWITCH_EXPRs in the future.  */
  
    opt_stats.num_exprs_considered++;
  
    /* Get a pointer to the expression we are trying to optimize.  */
!   if (TREE_CODE (stmt) == COND_EXPR)
!     expr_p = &COND_EXPR_COND (stmt);
!   else if (TREE_CODE (stmt) == SWITCH_EXPR)
!     expr_p = &SWITCH_COND (stmt);
    else if (TREE_CODE (stmt) == RETURN_EXPR && TREE_OPERAND (stmt, 0))
      expr_p = &TREE_OPERAND (TREE_OPERAND (stmt, 0), 1);
    else
--- 1835,1854 ----
  						     block_avail_exprs_p,
  						     ann,
  						     insert);
!   /* Similarly if this is a CF_EXPR and we did not find its
       expression in the hash table, simplify the condition and
       try again.  */
!   else if (! cached_lhs && TREE_CODE (stmt) == CF_EXPR)
      cached_lhs = simplify_cond_and_lookup_avail_expr (stmt,
  						      block_avail_exprs_p,
  						      ann,
  						      insert);
  
    opt_stats.num_exprs_considered++;
  
    /* Get a pointer to the expression we are trying to optimize.  */
!   if (TREE_CODE (stmt) == CF_EXPR)
!     expr_p = &CF_EXPR_COND (stmt);
    else if (TREE_CODE (stmt) == RETURN_EXPR && TREE_OPERAND (stmt, 0))
      expr_p = &TREE_OPERAND (TREE_OPERAND (stmt, 0), 1);
    else
*************** optimize_stmt (block_stmt_iterator si, v
*** 2126,2133 ****
  			       (TREE_OPERAND (TREE_OPERAND (stmt, 0), 1))))
  			|| (TREE_CODE (stmt) == MODIFY_EXPR
  			    && ! TREE_SIDE_EFFECTS (TREE_OPERAND (stmt, 1)))
! 			|| TREE_CODE (stmt) == COND_EXPR
! 			|| TREE_CODE (stmt) == SWITCH_EXPR));
  
    if (may_optimize_p)
      may_have_exposed_new_symbols
--- 2119,2125 ----
  			       (TREE_OPERAND (TREE_OPERAND (stmt, 0), 1))))
  			|| (TREE_CODE (stmt) == MODIFY_EXPR
  			    && ! TREE_SIDE_EFFECTS (TREE_OPERAND (stmt, 1)))
! 			|| TREE_CODE (stmt) == CF_EXPR));
  
    if (may_optimize_p)
      may_have_exposed_new_symbols
*************** optimize_stmt (block_stmt_iterator si, v
*** 2138,2156 ****
      record_equivalences_from_stmt (stmt, block_avail_exprs_p,
  				   may_optimize_p, ann);
  
!   /* If STMT is a COND_EXPR and it was modified, then we may know
       where it goes.  In which case we can remove some edges, simplify
       some PHI nodes, maybe even avoid optimizing some blocks completely,
       etc.  */
!   if (ann->modified)
!     {
!       if (TREE_CODE (stmt) == COND_EXPR)
! 	cfg_altered |= cleanup_cond_expr_graph (bb_for_stmt (stmt), si);
  
-       if (TREE_CODE (stmt) == SWITCH_EXPR)
- 	cfg_altered |= cleanup_switch_expr_graph (bb_for_stmt (stmt), si);
-     }
-                                                                                 
    return may_have_exposed_new_symbols;
  }
  
--- 2130,2143 ----
      record_equivalences_from_stmt (stmt, block_avail_exprs_p,
  				   may_optimize_p, ann);
  
!   /* If STMT is a CF_EXPR and it was modified, then we may know
       where it goes.  In which case we can remove some edges, simplify
       some PHI nodes, maybe even avoid optimizing some blocks completely,
       etc.  */
!   if (ann->modified
!       && TREE_CODE (stmt) == CF_EXPR)
!     cfg_altered |= cleanup_cf_expr_graph (bb_for_stmt (stmt), si);
  
    return may_have_exposed_new_symbols;
  }
  
*************** lookup_avail_expr (tree stmt, varray_typ
*** 2233,2242 ****
    /* Find the location of the expression we care about.  Unfortunately,
       its location differs depending on the type of statement we are
       examining.  */
!   if (TREE_CODE (stmt) == COND_EXPR)
!     rhs = COND_EXPR_COND (stmt);
!   else if (TREE_CODE (stmt) == SWITCH_EXPR)
!     rhs = SWITCH_COND (stmt);
    else if (TREE_CODE (stmt) == RETURN_EXPR
  	   && TREE_OPERAND (stmt, 0))
      rhs = TREE_OPERAND (TREE_OPERAND (stmt, 0), 1);
--- 2220,2227 ----
    /* Find the location of the expression we care about.  Unfortunately,
       its location differs depending on the type of statement we are
       examining.  */
!   if (TREE_CODE (stmt) == CF_EXPR)
!     rhs = CF_EXPR_COND (stmt);
    else if (TREE_CODE (stmt) == RETURN_EXPR
  	   && TREE_OPERAND (stmt, 0))
      rhs = TREE_OPERAND (TREE_OPERAND (stmt, 0), 1);
*************** get_eq_expr_value (tree if_stmt, int tru
*** 2400,2406 ****
  {
    tree cond, value;
  
!   cond = COND_EXPR_COND (if_stmt);
    value = NULL;
  
    /* If the conditional is a single variable 'X', return 'X = 1' for
--- 2385,2391 ----
  {
    tree cond, value;
  
!   cond = CF_EXPR_COND (if_stmt);
    value = NULL;
  
    /* If the conditional is a single variable 'X', return 'X = 1' for
*************** avail_expr_hash (const void *p)
*** 2479,2488 ****
    /* Find the location of the expression we care about.  Unfortunately,
       its location differs depending on the type of statement we are
       examining.  */
!   if (TREE_CODE (stmt) == COND_EXPR)
!     rhs = COND_EXPR_COND (stmt);
!   else if (TREE_CODE (stmt) == SWITCH_EXPR)
!     rhs = SWITCH_COND (stmt);
    else if (TREE_CODE (stmt) == RETURN_EXPR && TREE_OPERAND (stmt, 0))
      rhs = TREE_OPERAND (TREE_OPERAND (stmt, 0), 1);
    else
--- 2464,2471 ----
    /* Find the location of the expression we care about.  Unfortunately,
       its location differs depending on the type of statement we are
       examining.  */
!   if (TREE_CODE (stmt) == CF_EXPR)
!     rhs = CF_EXPR_COND (stmt);
    else if (TREE_CODE (stmt) == RETURN_EXPR && TREE_OPERAND (stmt, 0))
      rhs = TREE_OPERAND (TREE_OPERAND (stmt, 0), 1);
    else
*************** avail_expr_eq (const void *p1, const voi
*** 2511,2530 ****
    tree s1, s2, rhs1, rhs2;
  
    s1 = (tree) p1;
!   if (TREE_CODE (s1) == COND_EXPR)
!     rhs1 = COND_EXPR_COND (s1);
!   else if (TREE_CODE (s1) == SWITCH_EXPR)
!     rhs1 = SWITCH_COND (s1);
    else if (TREE_CODE (s1) == RETURN_EXPR && TREE_OPERAND (s1, 0))
      rhs1 = TREE_OPERAND (TREE_OPERAND (s1, 0), 1);
    else
      rhs1 = TREE_OPERAND (s1, 1);
  
    s2 = (tree) p2;
!   if (TREE_CODE (s2) == COND_EXPR)
!     rhs2 = COND_EXPR_COND (s2);
!   else if (TREE_CODE (s2) == SWITCH_EXPR)
!     rhs2 = SWITCH_COND (s2);
    else if (TREE_CODE (s2) == RETURN_EXPR && TREE_OPERAND (s2, 0))
      rhs2 = TREE_OPERAND (TREE_OPERAND (s2, 0), 1);
    else
--- 2494,2509 ----
    tree s1, s2, rhs1, rhs2;
  
    s1 = (tree) p1;
!   if (TREE_CODE (s1) == CF_EXPR)
!     rhs1 = CF_EXPR_COND (s1);
    else if (TREE_CODE (s1) == RETURN_EXPR && TREE_OPERAND (s1, 0))
      rhs1 = TREE_OPERAND (TREE_OPERAND (s1, 0), 1);
    else
      rhs1 = TREE_OPERAND (s1, 1);
  
    s2 = (tree) p2;
!   if (TREE_CODE (s2) == CF_EXPR)
!     rhs2 = CF_EXPR_COND (s2);
    else if (TREE_CODE (s2) == RETURN_EXPR && TREE_OPERAND (s2, 0))
      rhs2 = TREE_OPERAND (TREE_OPERAND (s2, 0), 1);
    else
Index: tree-ssa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/tree-ssa.c,v
retrieving revision 1.1.4.151
diff -c -3 -p -r1.1.4.151 tree-ssa.c
*** tree-ssa.c	12 Nov 2003 23:33:07 -0000	1.1.4.151
--- tree-ssa.c	14 Nov 2003 00:08:10 -0000
*************** static void rewrite_initialize_block (st
*** 177,183 ****
  static void rewrite_walk_stmts (struct dom_walk_data *, basic_block, tree);
  static void rewrite_add_phi_arguments (struct dom_walk_data *,
  				       basic_block, tree);
- static void delete_tree_ssa (tree);
  static void mark_def_sites (struct dom_walk_data *walk_data,
  			    basic_block bb,
  			    tree parent_block_last_stmt ATTRIBUTE_UNUSED);
--- 177,182 ----
*************** rewrite_out_of_ssa (tree fndecl, enum tr
*** 1901,1907 ****
      }
  
    /* Flush out flow graph and SSA data.  */
-   delete_tree_ssa (fndecl);
    delete_var_map (map);
    timevar_pop (TV_TREE_SSA_TO_NORMAL);
  }
--- 1900,1905 ----
*************** init_tree_ssa (void)
*** 2242,2248 ****
  
  /* Deallocate memory associated with SSA data structures for FNDECL.  */
  
! static void
  delete_tree_ssa (tree fndecl)
  {
    size_t i;
--- 2240,2246 ----
  
  /* Deallocate memory associated with SSA data structures for FNDECL.  */
  
! void
  delete_tree_ssa (tree fndecl)
  {
    size_t i;
*************** delete_tree_ssa (tree fndecl)
*** 2251,2260 ****
    walk_tree (&DECL_SAVED_TREE (fndecl), remove_annotations_r, NULL, NULL);
  
    /* Remove annotations from every referenced variable.  */
!   for (i = 0; i < num_referenced_vars; i++)
!     referenced_var (i)->common.ann = NULL;
  
-   referenced_vars = NULL;
    global_var = NULL_TREE;
    call_clobbered_vars = NULL;
  }
--- 2249,2261 ----
    walk_tree (&DECL_SAVED_TREE (fndecl), remove_annotations_r, NULL, NULL);
  
    /* Remove annotations from every referenced variable.  */
!   if (referenced_vars)
!     {
!       for (i = 0; i < num_referenced_vars; i++)
! 	referenced_var (i)->common.ann = NULL;
!       referenced_vars = NULL;
!     }
  
    global_var = NULL_TREE;
    call_clobbered_vars = NULL;
  }
*************** remove_annotations_r (tree *tp, int *wal
*** 2274,2287 ****
  
    /* If the node is not a container, then it has nothing interesting
       underneath it.  */
!   if (code != LOOP_EXPR
!       && code != COND_EXPR
!       && code != CATCH_EXPR
!       && code != TRY_CATCH_EXPR
!       && code != TRY_FINALLY_EXPR
        && code != SWITCH_EXPR
        && code != BIND_EXPR
!       && code != COMPOUND_EXPR)
      {
        *walk_subtrees = 0;
        return NULL_TREE;
--- 2275,2285 ----
  
    /* If the node is not a container, then it has nothing interesting
       underneath it.  */
!   if (code != COND_EXPR
        && code != SWITCH_EXPR
        && code != BIND_EXPR
!       && code != COMPOUND_EXPR
!       && code != STATEMENT_LIST)
      {
        *walk_subtrees = 0;
        return NULL_TREE;
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.263.2.67
diff -c -3 -p -r1.263.2.67 tree.c
*** tree.c	13 Nov 2003 02:38:01 -0000	1.263.2.67
--- tree.c	14 Nov 2003 00:08:10 -0000
*************** static const char * const tree_node_kind
*** 72,77 ****
--- 72,78 ----
    "temp_tree_lists",
    "vecs",
    "phi_nodes",
+   "cf_exprs",
    "ssa names",
    "random kinds",
    "lang_decl kinds",
*************** tree_size (tree node)
*** 194,199 ****
--- 195,204 ----
  					+ (PHI_ARG_CAPACITY (node) - 1) *
  					sizeof (struct phi_arg_d));
  
+ 	case CF_EXPR:		return (sizeof (struct tree_cf_expr)
+ 					+ (CF_EXPR_CAPACITY (node) - 1) *
+ 					sizeof (struct cf_alt_d));
+ 
  	case EPHI_NODE:		return (sizeof (struct tree_ephi_node)
  					+ (EPHI_ARG_CAPACITY (node) - 1) *
  					sizeof (struct ephi_arg_d));
*************** make_node (enum tree_code code)
*** 234,240 ****
  
    /* We can't allocate a TREE_VEC or PHI_NODE without knowing how many elements
       it will have.  */
!   if (code == TREE_VEC || code == PHI_NODE || code == EPHI_NODE)
      abort ();
  
    TREE_SET_CODE ((tree)&ttmp, code);
--- 239,245 ----
  
    /* We can't allocate a TREE_VEC or PHI_NODE without knowing how many elements
       it will have.  */
!   if (code == TREE_VEC || code == PHI_NODE || code == EPHI_NODE || code == CF_EXPR)
      abort ();
  
    TREE_SET_CODE ((tree)&ttmp, code);
*************** make_node (enum tree_code code)
*** 277,286 ****
      case 'x':  /* something random, like an identifier.  */
        if (code == IDENTIFIER_NODE)
  	kind = id_kind;
-       else if (code == TREE_VEC)
- 	kind = vec_kind;
-       else if (code == PHI_NODE)
- 	kind = phi_kind;
        else if (code == SSA_NAME)
  	kind = ssa_name_kind;
        else
--- 282,287 ----
*************** tree_node_structure (tree t)
*** 1499,1504 ****
--- 1500,1506 ----
      case TREE_LIST:		return TS_LIST;
      case TREE_VEC:		return TS_VEC;
      case PHI_NODE:		return TS_PHI_NODE;
+     case CF_EXPR:		return TS_CF_EXPR;
      case EPHI_NODE:		return TS_EPHI_NODE;
      case EUSE_NODE:             return TS_EUSE_NODE;
      case EKILL_NODE:            return TS_EREF_NODE;
*************** phi_node_elt_check_failed (int idx, int 
*** 4854,4859 ****
--- 4856,4873 ----
       idx + 1, len, function, trim_filename (file), line);
  }
  
+ /* Similar to above, except that the check is for the bounds of a CF_EXPR's
+    (dynamically sized) vector.  */
+ 
+ void
+ cf_expr_elt_check_failed (int idx, int len, const char *file, int line,
+ 			  const char *function)
+ {
+   internal_error
+     ("tree check: accessed elt %d of cf_expr with %d elts in %s, at %s:%d",
+      idx + 1, len, function, trim_filename (file), line);
+ }
+ 
  /* Similar to above, except that the check is for the bounds of the operand
     vector of an expression node.  */
  
*************** make_phi_node (tree var, int len)
*** 5165,5170 ****
--- 5179,5209 ----
    return phi;
  }
  
+ /* Return a new CF_EXPR for condition COND and LEN number of alternatives.  */
+ 
+ tree
+ make_cf_expr (tree cond, int len)
+ {
+   tree cf_expr;
+   int size;
+ 
+   size = sizeof (struct tree_cf_expr) + (len - 1) * sizeof (struct cf_alt_d);
+ 
+ #ifdef GATHER_STATISTICS
+   tree_node_counts[(int) cf_expr_kind]++;
+   tree_node_sizes[(int) cf_expr_kind] += size;
+ #endif
+ 
+   cf_expr = ggc_alloc_tree (size);
+   memset ((PTR) cf_expr, 0, size);
+ 
+   TREE_SET_CODE (cf_expr, CF_EXPR);
+   CF_EXPR_N_ALTS (cf_expr) = 0;
+   CF_EXPR_CAPACITY (cf_expr) = len;
+   CF_EXPR_COND (cf_expr) = cond;
+ 
+   return cf_expr;
+ }
  
  /* Resize an existing PHI node.  The only way is up.  Return the
     possibly relocated phi.  */
Index: tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.52.2.19
diff -c -3 -p -r1.52.2.19 tree.def
*** tree.def	12 Nov 2003 22:06:27 -0000	1.52.2.19
--- tree.def	14 Nov 2003 00:08:10 -0000
*************** DEFTREECODE (CATCH_EXPR, "catch_expr", '
*** 901,906 ****
--- 901,913 ----
     expanding.  */
  DEFTREECODE (EH_FILTER_EXPR, "eh_filter_expr", 's', 2)
  
+ /* Used to represent generic control flow.  CF_EXPR_COND is the value on that
+    the decision is based, CF_EXPR_N_ALTS is the number of alternatives (except for
+    case when value of condition is zero, then the edge with EDGE_ZERO_FLAG is
+    taken, and the default edge marked by EDGE_DEFAULT_FLAG), CF_EXPR_ALT(N) is the
+    pair (value, edge) for the Nth alternative.  */
+ DEFTREECODE (CF_EXPR, "cf_expr", 'x', 0)
+ 
  /* Used to chain children of container statements together.
     Use the interface in tree-interator.h to access this node.  */
  DEFTREECODE (STATEMENT_LIST, "statement_list", 'x', 0)
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.124
diff -c -3 -p -r1.342.2.124 tree.h
*** tree.h	13 Nov 2003 02:38:02 -0000	1.342.2.124
--- tree.h	14 Nov 2003 00:08:10 -0000
*************** struct tree_common GTY(())
*** 369,374 ****
--- 369,385 ----
  				 __FILE__, __LINE__, __FUNCTION__);	\
      &__t->phi.a[__i]; }))
  
+ #define CF_EXPR_ELT_CHECK(t, i) __extension__				\
+ (*({const tree __t = t;							\
+     const int __i = (i);						\
+     if (TREE_CODE (__t) != CF_EXPR)					\
+       tree_check_failed (__t, CF_EXPR,					\
+ 			 __FILE__, __LINE__, __FUNCTION__);		\
+     if (__i < 0 || (unsigned) __i >= __t->cf_expr.num_alts)		\
+       cf_expr_elt_check_failed (__i, __t->cf_expr.num_alts,		\
+ 				 __FILE__, __LINE__, __FUNCTION__);	\
+     &__t->cf_expr.a + __i; }))
+ 
  /* Special checks for TREE_OPERANDs.  */
  #define TREE_OPERAND_CHECK(T, I) __extension__				\
  (*({const tree __t = EXPR_CHECK (T);					\
*************** extern void tree_vec_elt_check_failed (i
*** 411,416 ****
--- 422,430 ----
  extern void phi_node_elt_check_failed (int, int, const char *,
  				       int, const char *)
      ATTRIBUTE_NORETURN;
+ extern void cf_expr_elt_check_failed (int, int, const char *,
+ 				       int, const char *)
+     ATTRIBUTE_NORETURN;
  extern void ephi_node_elt_check_failed (int, int, const char *,
  					int, const char *)
      ATTRIBUTE_NORETURN;
*************** extern void tree_operand_check_failed (i
*** 430,435 ****
--- 444,450 ----
  #define TREE_RTL_OPERAND_CHECK(T, CODE, I)  (*(rtx *) &((T)->exp.operands[I]))
  #define EREF_NODE_CHECK(T)		(T)
  #define PHI_NODE_ELT_CHECK(T, i)	((T)->phi.a[i])
+ #define CF_EXPR_ELT_CHECK(T, i)		((T)->cf_expr.a + i)
  #define EPHI_NODE_ELT_CHECK(T, i)	((T)->ephi.a[i])
  
  #endif
*************** struct tree_vec GTY(())
*** 919,931 ****
  #define EXPR_LOCUS(NODE)					\
    (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (NODE)))	\
     ? (NODE)->exp.locus						\
!    : (location_t *)NULL)
! #define SET_EXPR_LOCUS(NODE, FROM) \
!   (EXPR_CHECK (NODE)->exp.locus = (FROM))
  #define EXPR_FILENAME(NODE) \
!   (EXPR_CHECK (NODE)->exp.locus->file)
  #define EXPR_LINENO(NODE) \
!   (EXPR_CHECK (NODE)->exp.locus->line)
  
  /* In a TARGET_EXPR node.  */
  #define TARGET_EXPR_SLOT(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 0)
--- 934,950 ----
  #define EXPR_LOCUS(NODE)					\
    (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (NODE)))	\
     ? (NODE)->exp.locus						\
!    : (TREE_CODE (NODE) == CF_EXPR				\
!       ? (NODE)->cf_expr.locus					\
!       : (location_t *)NULL))
! #define SET_EXPR_LOCUS(NODE, FROM)				\
!   (TREE_CODE (NODE) == CF_EXPR					\
!    ? (CF_EXPR_CHECK (NODE)->cf_expr.locus = (FROM))		\
!    : (EXPR_CHECK (NODE)->exp.locus = (FROM)))
  #define EXPR_FILENAME(NODE) \
!   (EXPR_LOCUS (NODE)->file)
  #define EXPR_LINENO(NODE) \
!   (EXPR_LOCUS (NODE)->line)
  
  /* In a TARGET_EXPR node.  */
  #define TARGET_EXPR_SLOT(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 0)
*************** struct tree_phi_node GTY(())
*** 1063,1068 ****
--- 1082,1115 ----
  
    struct phi_arg_d GTY ((length ("((tree)&%h)->phi.capacity"))) a[1];
  };
+ 
+ /* Alternative of a CF_EXPR.  */
+ struct cf_alt_d GTY(())
+ {
+   tree low;
+   tree high;					/* Value.  */
+   struct edge_def * GTY((skip (""))) e;		/* The edge.  */
+ };
+ 
+ #define CF_EXPR_COND(NODE)	CF_EXPR_CHECK (NODE)->cf_expr.condition
+ #define CF_EXPR_CAPACITY(NODE)	CF_EXPR_CHECK (NODE)->cf_expr.max_alts
+ #define CF_EXPR_N_ALTS(NODE)	CF_EXPR_CHECK (NODE)->cf_expr.num_alts
+ #define CF_EXPR_ALT(NODE, I)	CF_EXPR_ELT_CHECK (NODE, I)
+ #define CF_EXPR_ALT_LOW(NODE, I)	CF_EXPR_ELT_CHECK (NODE, I)->low
+ #define CF_EXPR_ALT_HIGH(NODE, I)	CF_EXPR_ELT_CHECK (NODE, I)->high
+ #define CF_EXPR_ALT_EDGE(NODE, I)	CF_EXPR_ELT_CHECK (NODE, I)->e
+ 
+ /* The cf_expr node.  */
+ struct tree_cf_expr GTY(())
+ {
+   struct tree_common common;
+   location_t *locus;
+   tree condition;
+   unsigned max_alts;
+   unsigned num_alts;
+ 
+   struct cf_alt_d GTY ((length ("((tree)&%h)->cf_expr.max_alts"))) a[1];
+ };
  
  
  struct varray_head_tag;
*************** enum tree_node_structure_enum {
*** 2198,2203 ****
--- 2245,2251 ----
    TS_EXP,
    TS_SSA_NAME,
    TS_PHI_NODE,
+   TS_CF_EXPR,
    TS_EPHI_NODE,
    TS_EUSE_NODE,
    TS_EREF_NODE,
*************** union tree_node GTY ((ptr_alias (union l
*** 2227,2232 ****
--- 2275,2281 ----
    struct tree_exp GTY ((tag ("TS_EXP"))) exp;
    struct tree_ssa_name GTY ((tag ("TS_SSA_NAME"))) ssa_name;
    struct tree_phi_node GTY ((tag ("TS_PHI_NODE"))) phi;
+   struct tree_cf_expr GTY ((tag ("TS_CF_EXPR"))) cf_expr;
    struct tree_eref_common GTY ((tag ("TS_EREF_NODE"))) eref;
    struct tree_ephi_node GTY ((tag ("TS_EPHI_NODE"))) ephi;
    struct tree_euse_node GTY ((tag ("TS_EUSE_NODE"))) euse;
*************** extern void resize_phi_node (tree *, int
*** 2528,2533 ****
--- 2577,2585 ----
  extern tree make_ssa_name (tree, tree);
  extern tree build_vdef_expr (tree);
  
+ /* For representation of control flow.  */
+ extern tree make_cf_expr (tree, int);
+ 
  /* Return the (unique) IDENTIFIER_NODE node for a given name.
     The name is supplied as a char *.  */
  
*************** typedef enum
*** 3617,3622 ****
--- 3669,3675 ----
    temp_list_kind,
    vec_kind,
    phi_kind,
+   cf_expr_kind,
    ssa_name_kind,
    x_kind,
    lang_decl,


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