This is the mail archive of the gcc@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]

Re: Language-independent functions-as-trees representation


I'd like to bring this subject up yet again, last discussed in

  http://gcc.gnu.org/ml/gcc/2002-07/threads.html#00890

I continue to believe that the current tree IR is fundamentally flawed; it
was designed as a convenient shorthand for representing C parse trees, and
is fairly unwieldy for use by optimizers.  I laid out various problems in
the message above.  One primary weakness is that many of the _STMT
codes just mean "call expand_foo now", and as such are a reasonable
representation if we are only going to pass them to the expander, as has
been the case in the past, but not if we want them to actually express
program semantics in a properly structured way.

I also continue to take issue with the distinction between _STMT and _EXPR
nodes.  Discussing this with other folks, I have come to the conclusion
that the real distinction between statements and expressions is that a
statement is something for which we are only interested in its
side-effects, not its value.  It's a difference of evaluation context, not
always an intrinsic difference.  Something like a cleanup can appear in
either context; it seems sensible to use TRY_FINALLY_EXPR to express it in
both, rather than convert it to a TRY_FINALLY_STMT when it moves to
statement context.

I've been working for a couple of weeks off and on to retarget the
simplifier to generate something much more like the Java frontend tree IR,
which seems much cleaner to me, largely by virtue of working mostly in the
existing backend tree codes.  I've made a lot of progress, though
significant things are still broken, but my morale is fading.  I see more
and more people building things on the current IR every day, increasing the
work that will be necessary to switch optimizers and such over to the
hypothetical new scheme.

It seems to me that these fundamental design questions need to be
straightened out now, before we build anything more on top of the current
IR, or we're just digging ourselves a deeper hole.  As long as we're
building something new, we should take the time to do it right.  Do others
disagree?  I suppose another strategy would be to clean up the expand
placeholders in the C/C++ IR one by one, rather than try to simplify it to
something rather different all at once, but that would not address the
STMT/EXPR issue.

Basically, I'm wondering if other people are interested enough in this
change to 1) help with the design for the IR and 2) help with porting the
existing tree optimizers to the new IR.

In any case, here's a draft of a design of a new SIMPLE representation.
It's a bit sketchy at this point, but I'm very interested in comments.

------

   function:
     FUNCTION_DECL
       DECL_SAVED_TREE -> block
   block:
     BIND_EXPR
       BIND_EXPR_VARS -> DECL chain
       BIND_EXPR_BLOCK -> BLOCK
       BIND_EXPR_BODY -> compound-stmt

A BIND_EXPR takes the place of the current COMPOUND_STMT, SCOPE_STMT and
DECL_STMT; all of the decls for a block are given RTL at the beginning of
the block.  DECLs with static initializers keep their DECL_INITIAL; other
initializations are implemented with INIT_EXPRs in the codestream.  The
Java "BLOCK_EXPR" is very similar.

   compound-stmt:
     COMPOUND_EXPR
       op0 -> non-compound-stmt
       op1 -> stmt

rth has raised some questions about the advisability of using COMPOUND_EXPR
to chain statements; the current scheme uses TREE_CHAIN of the statements
themselves.  To me, the benefit is modularity; apart from the earlier
complaints about the STMT/EXPR distinction, using COMPOUND_EXPR makes it
easy to replace a single complex expression with a sequence of simple ones,
simply by plugging in a COMPOUND_EXPR in its place.  The current scheme
requires a lot more pointer management in order to splice the new STMTs in
at both ends.

It seems to me that double-chaining could be provided by using the
TREE_CHAIN of the COMPOUND_EXPRs.

   stmt: compound-stmt | non-compound-stmt
   non-compound-stmt:
     block
     | loop-stmt
     | if-stmt
     | switch-stmt
     | labeled-block-stmt
     | jump-stmt
     | label-stmt
     | try-stmt
     | modify-stmt
     | call-stmt
   loop-stmt:
     LOOP_EXPR
       LOOP_EXPR_BODY -> stmt | NULL_TREE
     | DO_LOOP_EXPR
       (to be defined later)

The Java loop has 1 (or 0) EXIT_EXPR, used to express the loop condition.
This makes it easy to distinguish from 'break's, which are expressed
with EXIT_BLOCK_EXPR.  

EXIT_EXPR is a bit backwards for this purpose, as its sense is opposite to
that of the loop condition, so we end up calling invert_truthvalue twice in
the process of generating and expanding it.  But that's not a big deal.

>From an optimization perspective, are LABELED_BLOCK_EXPR/EXIT_BLOCK_EXPR
easier to deal with than plain gotos?  I assume they're preferable to the
current loosely bound BREAK_STMT, which has no information about what it's
exiting.  EXIT_EXPR would have the same problem if it were used to express
'break'.

   if-stmt:
     COND_EXPR
       op0 -> condition
       op1 -> stmt
       op2 -> stmt
   switch-stmt:
     SWITCH_EXPR
       op0 -> val
       op1 -> stmt

The McCAT SIMPLE requires the simplifier to make case labels disjoint by
copying shared code around, allowing a more structured representation of a
switch.  I think this is too dubious an optimization to be performed by
default, but might be interesting as part of a goto-elimination pass; a
possible representation would be to also allow a TREE_LIST for op1.

   labeled-block-stmt:
     LABELED_BLOCK_EXPR
       op0 -> LABEL_DECL
       op1 -> stmt
   jump-stmt:
     EXIT_EXPR
         op0 -> condition
     | GOTO_EXPR
         op0 -> LABEL_DECL | '*' ID
     | RETURN_EXPR
         op0 -> modify-stmt | NULL_TREE

I had thought about always moving the assignment to the return value out of
the RETURN_EXPR, but it seems like expand_return depends on getting a
MODIFY_EXPR in order to handle some return semantics.

     | EXIT_BLOCK_EXPR
         op0 -> ref to LABELED_BLOCK_EXPR
         op1 -> NULL_TREE
     | THROW_EXPR? 

I'm not sure how we want to represent throws for the purpose of to
generating an ERT_THROW region?  I had thought about using a THROW_EXPR
wrapper, but that wouldn't work in non-simplified code where calls can have
complex args.  Perhaps annotation of the CALL_EXPR would work better.

     | RESX_EXPR
   label-stmt:
     LABEL_EXPR
         op0 -> LABEL_DECL
     | CASE_LABEL_EXPR
         CASE_LOW -> val | NULL_TREE
         CASE_HIGH -> val | NULL_TREE
   try-stmt:
     TRY_CATCH_EXPR

This will need to be extended to handle type-based catch clauses as well.

     | TRY_FINALLY_EXPR

I think it makes sense to leave this as a separate tree code for handling
cleanups.

   modify-stmt:
     MODIFY_EXPR | INIT_EXPR
       op0 -> lhs
       op1 -> rhs
   call-stmt: CALL_EXPR
     op0 -> ID
     op1 -> arglist

Assignment and calls are the only expressions with intrinsic side-effects,
so only they can appear at statement context.

The rest of this is basically copied from the McCAT design.  I think it
still needs some tweaking, but that can wait until after the
statement-level stuff is worked out.

   varname : compref | ID (rvalue)
   lhs: varname | '*' ID  (lvalue)
   pseudo-lval: ID | '*' ID  (either)
   compref :
     COMPONENT_REF
       op0 -> compref | pseudo-lval
     | ARRAY_REF
       op0 -> compref | pseudo-lval
       op1 -> val

   condition : val | val relop val
   val : ID | CONST

   rhs        : varname | CONST
	      | '*' ID
	      | '&' varname_or_temp
	      | call_expr
	      | unop val
	      | val binop val
	      | '(' cast ')' varname

   unop    : '+' | '-' | '!' | '~'
   binop   : relop | '-' | '+' | '/' | '*' | '%' | '&' | '|' | '<<' | '>>' | '^'
   relop   : '<' | '<=' | '>' | '>=' | '==' | '!='

-----
Other thoughts:

I've gotten questions about what GENERIC means, and whether it's worth
designing yet another IR.  I don't think any design is necessary; GENERIC
is just whatever can be expressed in the generic trees.  The l-i simplifier
should be able to reduce any valid tree structure to SIMPLE.

It's still not clear to me how best to represent line number information.
I'd appreciate someone from the Java team explaining to me how it's handled
there, particularly the use of EXPR_WFL_LINECOL on
non-EXPR_WITH_FILE_LOCATION nodes.

There has been uncertainty about what to do with frontend trees that we
want to wait and lower after inlining; the problem is how to treat them in
dataflow optimizations.  I think that we don't actually need to worry about
that; we can do more localized optimizations, such as inlining, and then
lower them to backend trees.

I've attached my current patch below; it's still in the toy stages, but
gives an idea of my implementation strategy.

Jason

*** ./cp/cp-tree.h.~1~	Mon Aug 12 03:14:19 2002
--- ./cp/cp-tree.h	Tue Aug 20 17:49:56 2002
*************** struct diagnostic_context;
*** 96,102 ****
        DECL_MUTABLE_P (in FIELD_DECL)
     1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
        DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
-       DECL_C_BITFIELD (in FIELD_DECL)
     2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
        DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL)
     3: DECL_IN_AGGR_P.
--- 96,101 ----
*** ./cp/semantics.c.~1~	Tue Aug 20 14:22:25 2002
--- ./cp/semantics.c	Wed Aug 21 12:45:23 2002
*************** nullify_returns_r (tp, walk_subtrees, da
*** 2506,2512 ****
    if (TYPE_P (*tp))
      *walk_subtrees = 0;
    else if (TREE_CODE (*tp) == RETURN_STMT)
!     RETURN_EXPR (*tp) = NULL_TREE;
    else if (TREE_CODE (*tp) == CLEANUP_STMT
  	   && CLEANUP_DECL (*tp) == nrv)
      CLEANUP_EH_ONLY (*tp) = 1;
--- 2506,2512 ----
    if (TYPE_P (*tp))
      *walk_subtrees = 0;
    else if (TREE_CODE (*tp) == RETURN_STMT)
!     RETURN_STMT_EXPR (*tp) = NULL_TREE;
    else if (TREE_CODE (*tp) == CLEANUP_STMT
  	   && CLEANUP_DECL (*tp) == nrv)
      CLEANUP_EH_ONLY (*tp) = 1;
*** ./cp/pt.c.~1~	Tue Aug 20 14:22:25 2002
--- ./cp/pt.c	Wed Aug 21 12:46:51 2002
*************** tsubst_expr (t, args, complain, in_decl)
*** 7382,7388 ****
  
      case RETURN_STMT:
        prep_stmt (t);
!       finish_return_stmt (tsubst_expr (RETURN_EXPR (t),
  				       args, complain, in_decl));
        break;
  
--- 7382,7388 ----
  
      case RETURN_STMT:
        prep_stmt (t);
!       finish_return_stmt (tsubst_expr (RETURN_STMT_EXPR (t),
  				       args, complain, in_decl));
        break;
  
*** ./c-decl.c.~1~	Tue Aug 20 14:31:04 2002
--- ./c-decl.c	Wed Aug 21 21:03:29 2002
*************** c_expand_body (fndecl, nested_p, can_def
*** 6521,6526 ****
--- 6521,6527 ----
    if (!flag_disable_simple
        && simplify_function_tree (fndecl))
      {
+ #if 0
        if (flag_mudflap)
  	{
  	  mudflap_c_function (fndecl);
*************** c_expand_body (fndecl, nested_p, can_def
*** 6532,6537 ****
--- 6533,6539 ----
        /* Invoke the SSA tree optimizer.  */
        if (flag_tree_ssa)
  	optimize_function_tree (fndecl);
+ #endif
      }
  
    /* Set up parameters and prepare for return, for the function.  */
*************** c_expand_body (fndecl, nested_p, can_def
*** 6545,6551 ****
      expand_main_function ();
  
    /* Generate the RTL for this function.  */
!   expand_stmt (DECL_SAVED_TREE (fndecl));
    if (uninlinable)
      {
        /* Allow the body of the function to be garbage collected.  */
--- 6547,6557 ----
      expand_main_function ();
  
    /* Generate the RTL for this function.  */
!   if (statement_code_p (TREE_CODE (DECL_SAVED_TREE (fndecl))))
!     expand_stmt (DECL_SAVED_TREE (fndecl));
!   else
!     expand_expr_stmt (DECL_SAVED_TREE (fndecl));
! 
    if (uninlinable)
      {
        /* Allow the body of the function to be garbage collected.  */
*** ./c-simplify.c.~1~	Tue Aug 20 14:31:04 2002
--- ./c-simplify.c	Thu Aug 22 18:02:48 2002
*************** Software Foundation, 59 Temple Place - S
*** 65,92 ****
  
  /* Local declarations.  */
  
! static void simplify_stmt            PARAMS ((tree *));
! static void simplify_expr_stmt       PARAMS ((tree, tree *, tree *));
! static void simplify_decl_stmt       PARAMS ((tree, tree *, tree *, tree *));
! static void simplify_for_stmt        PARAMS ((tree, tree *));
! static void simplify_while_stmt      PARAMS ((tree, tree *));
! static void simplify_do_stmt         PARAMS ((tree));
! static void simplify_if_stmt         PARAMS ((tree, tree *));
! static void simplify_switch_stmt     PARAMS ((tree, tree *));
! static void simplify_return_stmt     PARAMS ((tree, tree *));
  static void simplify_stmt_expr       PARAMS ((tree *, tree *));
! static void simplify_compound_literal_expr PARAMS ((tree *, tree *, tree *));
  static void make_type_writable       PARAMS ((tree));
- static tree insert_before_continue   PARAMS ((tree, tree));
- static tree tree_last_decl           PARAMS ((tree));
- static int  stmt_has_effect          PARAMS ((tree));
  static int  expr_has_effect          PARAMS ((tree));
  static tree mostly_copy_tree_r       PARAMS ((tree *, int *, void *));
  static inline void remove_suffix     PARAMS ((char *, int));
  static const char *get_name          PARAMS ((tree));
  static int is_last_stmt_of_scope     PARAMS ((tree));
- static tree tail_expression          PARAMS ((tree *, int));
  static tree mark_not_simple_r        PARAMS ((tree *, int *, void *));
  
  /* Should move to tree-simple.c when the target language loses the C-isms.  */
  static void simplify_constructor     PARAMS ((tree, tree *, tree *));
--- 65,95 ----
  
  /* Local declarations.  */
  
! static void c_simplify_stmt          PARAMS ((tree *));
! static void simplify_expr_stmt       PARAMS ((tree *));
! static void simplify_decl_stmt       PARAMS ((tree *));
! static void simplify_for_stmt        PARAMS ((tree *, tree *));
! static void simplify_while_stmt      PARAMS ((tree *));
! static void simplify_do_stmt         PARAMS ((tree *));
! static void simplify_if_stmt         PARAMS ((tree *));
! static void simplify_switch_stmt     PARAMS ((tree *));
! static void simplify_return_stmt     PARAMS ((tree *));
  static void simplify_stmt_expr       PARAMS ((tree *, tree *));
! static void simplify_compound_literal_expr PARAMS ((tree *, tree *));
  static void make_type_writable       PARAMS ((tree));
  static int  expr_has_effect          PARAMS ((tree));
  static tree mostly_copy_tree_r       PARAMS ((tree *, int *, void *));
  static inline void remove_suffix     PARAMS ((char *, int));
  static const char *get_name          PARAMS ((tree));
  static int is_last_stmt_of_scope     PARAMS ((tree));
  static tree mark_not_simple_r        PARAMS ((tree *, int *, void *));
+ static void simplify_block	     PARAMS ((tree *, tree *));
+ static tree simplify_c_loop	     PARAMS ((tree, tree, tree, int));
+ static void push_context             PARAMS ((void));
+ static void pop_context              PARAMS ((void));
+ static tree begin_labeled_block      PARAMS ((tree));
+ static tree finish_labeled_block     PARAMS ((tree, tree));
+ static void simplify_break_or_continue	PARAMS ((tree *));
  
  /* Should move to tree-simple.c when the target language loses the C-isms.  */
  static void simplify_constructor     PARAMS ((tree, tree *, tree *));
*************** static void simplify_cond_expr       PAR
*** 104,116 ****
  static void simplify_boolean_expr    PARAMS ((tree *, tree *));
  static void simplify_expr_wfl        PARAMS ((tree *, tree *, tree *,
                                                int (*) (tree)));
! static tree build_addr_expr	      PARAMS ((tree));
  
  
  /* Local variables.  */
  static FILE *dump_file;
  static int dump_flags;
  
  /* Simplification of statement trees.  */
  
  /*  Entry point to the simplification pass.  FNDECL is the FUNCTION_DECL
--- 107,179 ----
  static void simplify_boolean_expr    PARAMS ((tree *, tree *));
  static void simplify_expr_wfl        PARAMS ((tree *, tree *, tree *,
                                                int (*) (tree)));
! static tree build_addr_expr	     PARAMS ((tree));
! static tree add_stmt_to_compound	PARAMS ((tree, tree));
  
  
  /* Local variables.  */
  static FILE *dump_file;
  static int dump_flags;
  
+ struct c_simplify_ctx
+ {
+   tree current_labeled_block;	    /* List of currently nested
+ 				       labeled blocks. */
+   tree continue_id;
+   tree break_id;
+ } *ctxp;
+ 
+ #define PUSH_LABELED_BLOCK(B)				\
+   {							\
+     TREE_CHAIN (B) = ctxp->current_labeled_block;	\
+     ctxp->current_labeled_block = (B);			\
+   }
+ #define POP_LABELED_BLOCK() 						\
+   ctxp->current_labeled_block = TREE_CHAIN (ctxp->current_labeled_block)
+ 
+ static void
+ push_context ()
+ {
+   if (ctxp)
+     abort ();
+   ctxp = (struct c_simplify_ctx *) xcalloc (1, sizeof (struct c_simplify_ctx));
+   ctxp->continue_id = get_identifier ("continue");
+   ctxp->break_id = get_identifier ("break");
+ }
+ 
+ static void
+ pop_context ()
+ {
+   if (!ctxp || ctxp->current_labeled_block)
+     abort ();
+   free (ctxp);
+   ctxp = NULL;
+ }
+ 
+ static tree
+ begin_labeled_block (name)
+      tree name;
+ {
+   tree label = build_decl (LABEL_DECL, name, NULL_TREE);
+   tree block = build (LABELED_BLOCK_EXPR, void_type_node, label, NULL_TREE);
+   TREE_SIDE_EFFECTS (block) = 1;
+   PUSH_LABELED_BLOCK (block);
+   return block;
+ }
+ 
+ static tree
+ finish_labeled_block (block, body)
+      tree block, body;
+ {
+   POP_LABELED_BLOCK ();
+   if (TREE_USED (block))
+     {
+       LABELED_BLOCK_BODY (block) = body;
+       body = block;
+     }
+   return body;
+ }
+ 
  /* Simplification of statement trees.  */
  
  /*  Entry point to the simplification pass.  FNDECL is the FUNCTION_DECL
*************** int
*** 120,137 ****
  simplify_function_tree (fndecl)
       tree fndecl;
  {
!   tree fnbody, fntree;
    int done;
  
    /* Don't bother doing anything if the program has errors.  */
    if (errorcount || sorrycount)
      return 0;
    
!   fntree = DECL_SAVED_TREE (fndecl);
!   if (fntree == NULL_TREE || TREE_CODE (fntree) != COMPOUND_STMT)
!     return 0;
! 
!   fnbody = COMPOUND_BODY (fntree);
    if (fnbody == NULL_TREE)
      return 0;
  
--- 183,197 ----
  simplify_function_tree (fndecl)
       tree fndecl;
  {
!   tree fnbody;
!   tree block;
    int done;
  
    /* Don't bother doing anything if the program has errors.  */
    if (errorcount || sorrycount)
      return 0;
    
!   fnbody = DECL_SAVED_TREE (fndecl);
    if (fnbody == NULL_TREE)
      return 0;
  
*************** simplify_function_tree (fndecl)
*** 155,174 ****
    pushlevel (0);
  
    /* Simplify the function's body.  */
!   done = simplify_expr (&fnbody, NULL, NULL, NULL, fb_rvalue);
  
!   /* Return if simplification failed.  */
!   if (!done)
!     {
!       poplevel (1, 1, 0);
!       return 0;
!     }
  
    /* Declare the new temporary variables.  */
!   declare_tmp_vars (getdecls(), fnbody);
! 
!   /* Restore the binding level.  */
!   poplevel (1, 1, 0);
  
    /* Debugging dump after simplification.  */
    dump_file = dump_begin (TDI_simple, &dump_flags);
--- 215,228 ----
    pushlevel (0);
  
    /* Simplify the function's body.  */
!   done = simplify_stmt (&fnbody);
!   DECL_SAVED_TREE (fndecl) = fnbody;
  
!   /* Restore the binding level.  */
!   block = poplevel (1, 1, 0);
  
    /* Declare the new temporary variables.  */
!   declare_tmp_vars (BLOCK_VARS (block), fnbody);
  
    /* Debugging dump after simplification.  */
    dump_file = dump_begin (TDI_simple, &dump_flags);
*************** simplify_function_tree (fndecl)
*** 185,191 ****
        dump_end (TDI_simple, dump_file);
      }
  
!   return 1;
  }
  
  
--- 239,245 ----
        dump_end (TDI_simple, dump_file);
      }
  
!   return done;
  }
  
  
*************** simplify_function_tree (fndecl)
*** 193,201 ****
      *STMT_P and convert it to a SIMPLE tree.  */
  
  static void 
! simplify_stmt (stmt_p)
       tree *stmt_p;
  {
    /* PRE and POST are tree chains that contain the side-effects of the
       simplified tree.  For instance, given the expression tree:
  
--- 247,258 ----
      *STMT_P and convert it to a SIMPLE tree.  */
  
  static void 
! c_simplify_stmt (stmt_p)
       tree *stmt_p;
  {
+   tree stmt, next;
+   tree outer_pre = NULL_TREE;
+ 
    /* PRE and POST are tree chains that contain the side-effects of the
       simplified tree.  For instance, given the expression tree:
  
*************** simplify_stmt (stmt_p)
*** 208,226 ****
       		c = t1 + b;
       		b = b + 1;	<-- POST  */
  
!   while (*stmt_p && *stmt_p != error_mark_node)
      {
!       tree next, pre, post;
!       int keep_stmt_p;
!       tree stmt = *stmt_p;
        int saved_stmts_are_full_exprs_p;
  
        /* Set up context appropriately for handling this statement.  */
        saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
        prep_stmt (stmt);
  
!       pre = NULL;
!       post = NULL;
  
        if (dump_file && (dump_flags & TDF_DETAILS))
  	{
--- 265,283 ----
       		c = t1 + b;
       		b = b + 1;	<-- POST  */
  
!   for (stmt = *stmt_p; stmt && stmt != error_mark_node; stmt = next)
      {
!       tree pre, post;
        int saved_stmts_are_full_exprs_p;
  
        /* Set up context appropriately for handling this statement.  */
        saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
        prep_stmt (stmt);
  
!       pre = NULL_TREE;
!       post = NULL_TREE;
! 
!       next = TREE_CHAIN (stmt);
  
        if (dump_file && (dump_flags & TDF_DETAILS))
  	{
*************** simplify_stmt (stmt_p)
*** 232,296 ****
        switch (TREE_CODE (stmt))
  	{
  	case COMPOUND_STMT:
! 	  simplify_stmt (&COMPOUND_BODY (stmt));
! 	  stmt_p = &TREE_CHAIN (stmt);
! 	  goto cont;
! 	  
  	case FOR_STMT:
! 	  simplify_for_stmt (stmt, &pre);
  	  break;
  	  
  	case WHILE_STMT:
! 	  simplify_while_stmt (stmt, &pre);
  	  break;
  
  	case DO_STMT:
! 	  simplify_do_stmt (stmt);
  	  break;
  
  	case IF_STMT:
! 	  simplify_if_stmt (stmt, &pre);
  	  break;
  	  
  	case SWITCH_STMT:
! 	  simplify_switch_stmt (stmt, &pre);
  	  break;
  
  	case EXPR_STMT:
! 	  simplify_expr_stmt (stmt, &pre, &post);
  	  break;
  
  	case RETURN_STMT:
! 	  simplify_return_stmt (stmt, &pre);
  	  break;
  
  	case DECL_STMT:
! 	  simplify_decl_stmt (stmt, &pre, &post, &post);
  	  break;
  
! 	case CLEANUP_STMT:
! 	  /* XXX: need to clean up CLEANUP_STMT.  Idea: turn it into
! 	     an statement-expression and simplify that.  */
  	  break;
  
- 	/* Statements that need no simplification.  */
- 	case LABEL_STMT:
  	case GOTO_STMT:
! 	case ASM_STMT:
  	case CASE_LABEL:
  	case CONTINUE_STMT:
  	case BREAK_STMT:
! 	case SCOPE_STMT:
! 	  stmt_p = &TREE_CHAIN (stmt);
  	  goto cont;
  
  	case FILE_STMT:
  	  input_filename = FILE_STMT_FILENAME (stmt);
- 	  stmt_p = &TREE_CHAIN (stmt);
  	  goto cont;
  
  	default:
! 	  fprintf (stderr, "unhandled statement node in simplify_stmt ():\n");
  	  debug_tree (stmt);
  	  abort ();
  	  break;
--- 289,363 ----
        switch (TREE_CODE (stmt))
  	{
  	case COMPOUND_STMT:
! 	  c_simplify_stmt (&COMPOUND_BODY (stmt));
! 	  stmt = COMPOUND_BODY (stmt);
! 	  break;
! 
! 	case SCOPE_STMT:
! 	  simplify_block (&stmt, &next);
! 	  break;
! 
  	case FOR_STMT:
! 	  simplify_for_stmt (&stmt, &pre);
  	  break;
  	  
  	case WHILE_STMT:
! 	  simplify_while_stmt (&stmt);
  	  break;
  
  	case DO_STMT:
! 	  simplify_do_stmt (&stmt);
  	  break;
  
  	case IF_STMT:
! 	  simplify_if_stmt (&stmt);
  	  break;
  	  
  	case SWITCH_STMT:
! 	  simplify_switch_stmt (&stmt);
  	  break;
  
  	case EXPR_STMT:
! 	  simplify_expr_stmt (&stmt);
  	  break;
  
  	case RETURN_STMT:
! 	  simplify_return_stmt (&stmt);
  	  break;
  
  	case DECL_STMT:
! 	  simplify_decl_stmt (&stmt);
  	  break;
  
! 	case LABEL_STMT:
! 	  stmt = build (LABEL_EXPR, void_type_node, LABEL_STMT_LABEL (stmt));
  	  break;
  
  	case GOTO_STMT:
! 	  stmt = build (GOTO_EXPR, void_type_node, GOTO_DESTINATION (stmt));
! 	  break;
! 
  	case CASE_LABEL:
+ 	  stmt = build (CASE_LABEL_EXPR, void_type_node,
+ 			CASE_LOW (stmt), CASE_HIGH (stmt));
+ 	  break;
+ 
  	case CONTINUE_STMT:
  	case BREAK_STMT:
! 	  simplify_break_or_continue (&stmt);
! 	  break;
! 
! 	case CLEANUP_STMT:
! 	case ASM_STMT:
! 	  abort ();
  	  goto cont;
  
  	case FILE_STMT:
  	  input_filename = FILE_STMT_FILENAME (stmt);
  	  goto cont;
  
  	default:
! 	  fprintf (stderr, "unhandled statement node in c_simplify_stmt ():\n");
  	  debug_tree (stmt);
  	  abort ();
  	  break;
*************** simplify_stmt (stmt_p)
*** 299,313 ****
        /* PRE and POST now contain a list of statements for all the
  	 side-effects in STMT.  */
  
-       /* Before re-chaining the side effects, determine if we are going to
- 	 keep the original statement or not.  If the statement had no
- 	 effect before simplification, we emit it anyway to avoid changing
- 	 the semantics of the original program.  */
-       keep_stmt_p = stmt_has_effect (stmt);
-       
-       next = TREE_CHAIN (stmt);
-       TREE_CHAIN (stmt) = NULL_TREE;
- 
        /* Dump the side-effects and the simplified statement.  */
        if (dump_file && (dump_flags & TDF_DETAILS))
  	{
--- 366,371 ----
*************** simplify_stmt (stmt_p)
*** 324,348 ****
  	  fprintf (dump_file, "\n");
  	}
  
!       if (keep_stmt_p)
! 	pre = chainon (pre, stmt);
!       pre = chainon (pre, post);
!       *stmt_p = pre;
! 
!       /* Next iteration.  Re-set PREV to the last statement of the chain
! 	 PREV -> PRE -> STMT -> POST.  */
!       if (*stmt_p)
! 	{
! 	  stmt = tree_last (*stmt_p);
! 	  stmt_p = &TREE_CHAIN (stmt);
! 	}
!       *stmt_p = next;
  
      cont:
        /* Restore saved state.  */
        current_stmt_tree ()->stmts_are_full_exprs_p
  	= saved_stmts_are_full_exprs_p;
      }
  }
  
  /*  Simplify an EXPR_STMT node.
--- 382,468 ----
  	  fprintf (dump_file, "\n");
  	}
  
!       /* Before re-chaining the side effects, determine if we are going to
! 	 keep the original statement or not.  If the statement had no
! 	 effect before simplification, we emit it anyway to avoid changing
! 	 the semantics of the original program.  */
!       
!       add_tree (pre, &outer_pre);
!       add_tree (stmt, &outer_pre);
!       add_tree (post, &outer_pre);
  
      cont:
        /* Restore saved state.  */
        current_stmt_tree ()->stmts_are_full_exprs_p
  	= saved_stmts_are_full_exprs_p;
      }
+   add_tree (stmt, &outer_pre);
+   *stmt_p = rationalize_compound_expr (outer_pre);
+ }
+ 
+ static void
+ simplify_break_or_continue (stmt_p)
+      tree *stmt_p;
+ {
+   tree stmt = *stmt_p;
+   tree labeled_block;
+   tree target_name;
+ 
+   if (TREE_CODE (stmt) == BREAK_STMT)
+     target_name = ctxp->break_id;
+   else
+     target_name = ctxp->continue_id;
+ 
+   for (labeled_block = ctxp->current_labeled_block; ;
+        labeled_block = TREE_CHAIN (labeled_block))
+     if (DECL_NAME (LABELED_BLOCK_LABEL (labeled_block)) == target_name)
+       break;
+ 
+   TREE_USED (labeled_block) = 1;
+   *stmt_p = build (EXIT_BLOCK_EXPR, void_type_node, labeled_block, NULL_TREE);
+ }
+ 
+ static void
+ simplify_block (stmt_p, next_p)
+      tree *stmt_p;
+      tree *next_p;
+ {
+   tree *p;
+   tree block;
+   tree bind;
+   int depth;
+ 
+   if (!SCOPE_BEGIN_P (*stmt_p))
+     abort ();
+ 
+   block = SCOPE_STMT_BLOCK (*stmt_p);
+ 
+   /* Find the matching ending SCOPE_STMT.  */
+   depth = 1;
+   for (p = &TREE_CHAIN (*stmt_p);; p = &TREE_CHAIN (*p))
+     if (TREE_CODE (*p) == SCOPE_STMT)
+       {
+ 	if (SCOPE_PARTIAL_P (*p))
+ 	  /* Throw away partial scopes.  Hmm, that probably won't work;
+ 	     we need to remember them to handle goto cleanups.  */
+ 	  abort ();
+ 	else if (SCOPE_BEGIN_P (*p))
+ 	  ++depth;
+ 	else if (--depth == 0)
+ 	  break;
+       }
+   if (SCOPE_STMT_BLOCK (*p) != block)
+     abort ();
+ 
+   *next_p = TREE_CHAIN (*p);
+   *p = NULL_TREE;
+ 
+   bind = build (BIND_EXPR, void_type_node,
+ 		block ? BLOCK_VARS (block) : NULL_TREE,
+ 		TREE_CHAIN (*stmt_p), block);
+   TREE_SIDE_EFFECTS (bind) = 1;
+   c_simplify_stmt (&BIND_EXPR_BODY (bind));
+   *stmt_p = bind;
  }
  
  /*  Simplify an EXPR_STMT node.
*************** simplify_stmt (stmt_p)
*** 356,366 ****
  	STMT should be stored.  */
  
  static void
! simplify_expr_stmt (stmt, pre_p, post_p)
!      tree stmt;
!      tree *pre_p;
!      tree *post_p;
  {
    /* Simplification of a statement expression will nullify the
       statement if all its side effects are moved to *PRE_P and *POST_P.
  
--- 476,486 ----
  	STMT should be stored.  */
  
  static void
! simplify_expr_stmt (stmt_p)
!      tree *stmt_p;
  {
+   tree stmt = EXPR_STMT_EXPR (*stmt_p);
+ 
    /* Simplification of a statement expression will nullify the
       statement if all its side effects are moved to *PRE_P and *POST_P.
  
*************** simplify_expr_stmt (stmt, pre_p, post_p)
*** 369,569 ****
       simplification.  */
    if (extra_warnings || warn_unused_value)
      {
!       const char *fname = DECL_SOURCE_FILE (current_function_decl);
!       int lineno = STMT_LINENO (stmt);
! 
!       if (!stmt_has_effect (stmt))
! 	warning_with_file_and_line (fname, lineno, "statement with no effect");
        else if (warn_unused_value)
! 	{
! 	  set_file_and_line_for_stmt (fname, lineno);
! 	  warn_if_unused_value (EXPR_STMT_EXPR (stmt));
! 	}
      }
  
!   walk_tree (&EXPR_STMT_EXPR (stmt), mostly_copy_tree_r, NULL, NULL);
!   simplify_expr (&EXPR_STMT_EXPR (stmt), pre_p, post_p, is_simple_expr,
!                  fb_rvalue);
  }
  
! /*  Simplify a FOR_STMT node.  This will convert:
! 
!     	for (init; cond; expr)
! 	  {
! 	    body;
! 	  }
! 
!     into
! 
!     	pre_init_s;
! 	init_s;
! 	post_init_s;
! 	pre_cond_s;
! 	for ( ; cond_s; )
! 	  {
! 	    body;
! 	    pre_expr_s;
! 	    expr_s;
! 	    post_expr_s;
! 	    pre_cond_s;
! 	  }
! 
!     where INIT_S, COND_S and EXPR_S are the simplified versions of INIT,
!     COND and EXPR respectively.  PRE_*_S and POST_*_S are the side-effects
!     for each expression in the header.
! 
!     Note that the above form is the more general case, other variations are
!     possible if any of the PRE_*_S or POST_*S expressions are missing.
! 
!     The order in which the different pieces are simplified is also
!     important.  Simplification should be done in the same order in which
!     the loop will execute at runtime.
! 
!     PRE_P points to the list where side effects that must happen before
! 	STMT should be store.  These are all the expressions in
! 	FOR_INIT_STMT and the pre side-effects of the loop conditional.  */
! 
! static void
! simplify_for_stmt (stmt, pre_p)
!      tree stmt;
!      tree *pre_p;
  {
!   int init_is_simple, cond_is_simple, expr_is_simple;
!   tree pre_init_s, init_s, post_init_s;
!   tree pre_cond_s, cond_s;
!   tree pre_expr_s, expr_s, post_expr_s;
  
!   /* Make sure that the loop body has a scope.  */
!   tree_build_scope (&FOR_BODY (stmt));
  
!   /* If FOR_INIT_STMT is a DECL_STMT (C99), move it outside the loop and
!      replace it with an empty expression statement.  */
  
!   if (TREE_CODE (FOR_INIT_STMT (stmt)) == DECL_STMT)
!     {
!       tree decl_s = FOR_INIT_STMT (stmt);
!       pre_init_s = NULL_TREE;
!       simplify_decl_stmt (decl_s, pre_p, &pre_init_s, &pre_init_s);
!       add_tree (decl_s, pre_p);
!       add_tree (pre_init_s, pre_p);
!       FOR_INIT_STMT (stmt) = build_stmt (EXPR_STMT, NULL_TREE);
!     }
  
!   init_s = EXPR_STMT_EXPR (FOR_INIT_STMT (stmt));
!   cond_s = FOR_COND (stmt);
!   expr_s = FOR_EXPR (stmt);
  
!   /* Check if we need to do anything.  */
!   init_is_simple = (init_s == NULL_TREE || is_simple_exprseq (init_s));
!   cond_is_simple = (cond_s == NULL_TREE || is_simple_condexpr (cond_s));
!   expr_is_simple = (expr_s == NULL_TREE || is_simple_exprseq (expr_s));
  
!   if (init_is_simple && cond_is_simple && expr_is_simple)
!     {
!       /* Nothing to do, simplify the body and return.  */
!       simplify_stmt (&FOR_BODY (stmt));
!       return;
!     }
  
!   pre_init_s = NULL_TREE;
!   post_init_s = NULL_TREE;
!   pre_cond_s = NULL_TREE;
!   pre_expr_s = NULL_TREE;
!   post_expr_s = NULL_TREE;
! 
!   /* Simplify FOR_INIT_STMT.  Note that we always simplify it, even if it's
!      in SIMPLE form already.  This is because we need to insert PRE_COND_S
!      right after the initialization statements, and if PRE_COND_S contains
!      statement trees, we cannot add them to a COMPOUND_EXPR:
! 
! 	BEFORE				AFTER
! 
! 					pre_init_s;
! 					init_s;
! 					post_init_s;
! 					pre_cond_s;
! 	for (init; cond; ...)		for ( ; cond_s; ...)
! 
!      FIXME: Since FOR_INIT_STMT can be a COMPOUND_EXPR, it should be possible
! 	    to emit PRE_INIT_S, INIT_S, POST_INIT_S and PRE_COND_S into a
! 	    COMPOUND_EXPR inside FOR_INIT_STMT.  However, this is not
! 	    possible if any of these elements contains statement trees.  */
!   walk_tree (&init_s, mostly_copy_tree_r, NULL, NULL);
!   simplify_expr (&init_s, &pre_init_s, &post_init_s, is_simple_expr,
! 		 fb_rvalue);
  
!   /* Simplify FOR_COND.  */
!   if (!cond_is_simple)
!     {
!       walk_tree (&cond_s, mostly_copy_tree_r, NULL, NULL);
!       simplify_expr (&cond_s, &pre_cond_s, NULL, is_simple_condexpr,
! 		     fb_rvalue);
!     }
  
!   /* Simplify the body of the loop.  */
!   simplify_stmt (&FOR_BODY (stmt));
  
!   /* Simplify FOR_EXPR.  Note that if FOR_EXPR needs to be simplified,
!      it's converted into a simple_expr because we need to move it out of
!      the loop header (see previous FIXME note for future enhancement).  */
!   if (!expr_is_simple)
!     {
!       walk_tree (&expr_s, mostly_copy_tree_r, NULL, NULL);
!       simplify_expr (&expr_s, &pre_expr_s, &post_expr_s, is_simple_expr,
! 		     fb_rvalue);
!     }  
  
!   /* Now that all the components are simplified, we have to build a new
!      loop with all the side-effects in the right spots:
  
!     	pre_init_s;
! 	init_s;
! 	post_init_s;
! 	pre_cond_s;
! 	for ( ; cond_s; )
  	  {
  	    body;
- 	    pre_expr_s;
- 	    expr_s;
- 	    post_expr_s;
- 	    pre_cond_s;
  	  }
  
!      The above is the more general case, which produces a for() loop that
!      doesn't resemble the original.  To minimize shape changes, we try to
!      insert expressions in FOR_INIT_STMT and FOR_EXPR.  */
! 
!   /* Link PRE_INIT_S, INIT_S, POST_INIT_S and a copy of PRE_COND_S to make
!      up a new FOR_INIT_STMT.  If the last tree in the list is an expression
!      tree, it is emmitted inside FOR_INIT_STMT.  We emit a copy of
!      PRE_COND_S because we also need to emit it at every wrap-around point
!      in the loop body.  */
!   add_tree (pre_init_s, pre_p);
!   add_tree (init_s, pre_p);
!   add_tree (post_init_s, pre_p);
!   add_tree (deep_copy_list (pre_cond_s), pre_p);
! 
!   EXPR_STMT_EXPR (FOR_INIT_STMT (stmt)) = deep_copy_list (tail_expression (pre_p, 0));
! 
!   /* Build the new FOR_COND.  */
!   FOR_COND (stmt) = cond_s;
! 
!   /* Link PRE_EXPR_S, EXPR_S, POST_EXPR_S and PRE_COND_S to emit before
!      every wrap-around point inside the loop body.  If the last tree in the
!      list is an expression tree, it is emitted inside FOR_EXPR.  */
!   {
!     tree expr_chain;
! 
!     expr_chain = pre_expr_s;
!     add_tree (expr_s, &expr_chain);
!     add_tree (post_expr_s, &expr_chain);
!     add_tree (pre_cond_s, &expr_chain);
  
!     FOR_EXPR (stmt) = deep_copy_list (tail_expression (&expr_chain, 1));
  
!     if (expr_chain)
!       insert_before_continue_end (expr_chain, FOR_BODY (stmt));
!   }
  }
  
  
--- 489,577 ----
       simplification.  */
    if (extra_warnings || warn_unused_value)
      {
!       if (!expr_has_effect (stmt))
! 	warning ("statement with no effect");
        else if (warn_unused_value)
! 	warn_if_unused_value (stmt);
      }
  
!   *stmt_p = stmt;
  }
  
! static tree
! simplify_c_loop (cond, body, incr, cond_is_first)
!      tree cond;
!      tree body;
!      tree incr;
!      int cond_is_first;
  {
!   tree exit, cont_block, break_block, loop;
  
!   break_block = begin_labeled_block (ctxp->break_id);
  
!   loop = build (LOOP_EXPR, void_type_node, NULL_TREE);
!   TREE_SIDE_EFFECTS (loop) = 1;
  
!   if (cond)
!     exit = build (EXIT_EXPR, void_type_node, invert_truthvalue (cond));
!   else
!     exit = NULL_TREE;
  
!   cont_block = begin_labeled_block (ctxp->continue_id);
  
!   c_simplify_stmt (&body);
  
!   body = finish_labeled_block (cont_block, body);
  
!   body = add_stmt_to_compound (body, incr);
!   if (cond_is_first)
!     body = add_stmt_to_compound (exit, body);
!   else
!     body = add_stmt_to_compound (body, exit);
  
!   LOOP_EXPR_BODY (loop) = body;
  
!   loop = finish_labeled_block (break_block, loop);
  
!   return loop;
! }
  
! /*  Simplify a FOR_STMT node.  This will convert:
  
!     	for (init; cond; expr)
  	  {
  	    body;
  	  }
  
!     into
  
!         init
!         LOOP_EXPR
! 	  COMPOUND_EXPR
! 	    EXIT_EXPR
! 	      cond
! 	    COMPOUND_EXPR
! 	      LABELED_BLOCK_EXPR
! 	        body
! 	      expr
  
!     PRE_P points to the list where side effects that must happen before
! 	STMT should be store.  These are all the expressions in
! 	FOR_INIT_STMT and the pre side-effects of the loop conditional.  */
! 
! static void
! simplify_for_stmt (stmt_p, pre_p)
!      tree *stmt_p;
!      tree *pre_p;
! {
!   tree stmt = *stmt_p;
! 
!   tree init = FOR_INIT_STMT (stmt);
!   c_simplify_stmt (&init);
!   add_tree (init, pre_p);
! 
!   *stmt_p = simplify_c_loop (FOR_COND (stmt), FOR_BODY (stmt),
! 			     FOR_EXPR (stmt), 1);
  }
  
  
*************** simplify_for_stmt (stmt, pre_p)
*** 576,598 ****
  
      into
  
! 	pre_cond_s;
!     	while (cond_s)
! 	  {
! 	    body;
! 	    pre_cond_s;
! 	  }
! 
!     where COND_S is the simplified version of the loop predicate.
!     PRE_COND_S are the pre side-effects produced by the simplification of
!     the conditional.
!     
!     These side-effects will be replicated at every wrap-around point inside
!     the loop's body.
! 
!     The order in which the different pieces are simplified is also
!     important.  Simplification should be done in the same order in which
!     the loop will execute at runtime.
  
      STMT is the statement to simplify.
  
--- 584,595 ----
  
      into
  
!         LOOP_EXPR
! 	  COMPOUND_EXPR
! 	    EXIT_EXPR
! 	      cond
! 	    LABELED_BLOCK_EXPR
! 	      body
  
      STMT is the statement to simplify.
  
*************** simplify_for_stmt (stmt, pre_p)
*** 600,642 ****
  	STMT should be stored.  */
  
  static void
! simplify_while_stmt (stmt, pre_p)
!      tree stmt;
!      tree *pre_p;
  {
!   tree cond_s, stmt_chain;
!   tree pre_cond_s = NULL_TREE;
! 
!   cond_s = WHILE_COND (stmt);
!   
!   /* Make sure that the loop body has a scope.  */
!   tree_build_scope (&WHILE_BODY (stmt));
!   
!   /* Simplify the body of the loop.  */
!   simplify_stmt (&WHILE_BODY (stmt)); 
! 
!   /* Check wether the loop condition is already simplified.  */
!   if (is_simple_condexpr (WHILE_COND (stmt)))
!     {
!       /* Nothing to do.  */
!       return;
!     }
!     
!   /* Simplify the loop conditional.  */
!   walk_tree (&cond_s, mostly_copy_tree_r, NULL, NULL);
!   simplify_expr (&cond_s, &pre_cond_s, NULL, is_simple_condexpr,
! 		 fb_rvalue);
!   WHILE_COND (stmt) = cond_s;
!   add_tree (pre_cond_s, pre_p);
! 
!   /* Insert all the side-effects for the conditional before every
!      wrap-around point in the loop body (i.e., before every first-level
!      CONTINUE and before the end of the body).  */
!   stmt_chain = deep_copy_list (pre_cond_s);
!   insert_before_continue_end (stmt_chain, WHILE_BODY (stmt));
  }
  
- 
  /*  Simplify a DO_STMT node.  This will convert:
  
  	do
--- 597,610 ----
  	STMT should be stored.  */
  
  static void
! simplify_while_stmt (stmt_p)
!      tree *stmt_p;
  {
!   tree stmt = *stmt_p;
!   *stmt_p = simplify_c_loop (WHILE_COND (stmt), WHILE_BODY (stmt),
! 			     NULL_TREE, 1);
  }
  
  /*  Simplify a DO_STMT node.  This will convert:
  
  	do
*************** simplify_while_stmt (stmt, pre_p)
*** 647,701 ****
  
      into
  
!     	do
! 	  {
! 	    body;
! 	    pre_cond_s;
! 	  }
!     	while (cond_s);
! 
!     where COND_S is the simplified version of the loop predicate.
!     PRE_COND_S are the pre side-effects produced by the simplification of
!     the conditional.
! 
!     These side-effects will be replicated at every wrap-around point inside
!     the loop's body.
! 
!     The order in which the different pieces are simplified is also
!     important.  Simplification should be done in the same order in which
!     the loop will execute at runtime.
  
      STMT is the statement to simplify.  */
  
  static void
! simplify_do_stmt (stmt)
!      tree stmt;
  {
!   tree cond_s, pre_cond_s, stmt_chain;
! 
!   /* Make sure that the loop body has a scope.  */
!   tree_build_scope (&DO_BODY (stmt));
! 
!   /* Simplify the loop's body.  */
!   simplify_stmt (&DO_BODY (stmt));
! 
!   /* Check wether the loop condition is already simplified.  */
!   if (is_simple_condexpr (DO_COND (stmt)))
!     return;
! 
!   /* Simplify the loop conditional.  */
!   pre_cond_s = NULL;
!   cond_s = DO_COND (stmt);
!   walk_tree (&cond_s, mostly_copy_tree_r, NULL, NULL);
!   simplify_expr (&cond_s, &pre_cond_s, NULL, is_simple_condexpr,
! 		 fb_rvalue);
!   DO_COND (stmt) = cond_s;
! 
!   stmt_chain = deep_copy_list (pre_cond_s);
!   insert_before_continue_end (stmt_chain, DO_BODY (stmt));
  }
  
- 
  /*  Simplify an IF_STMT.  This will convert:
  
      	if (cond)
--- 615,638 ----
  
      into
  
!         LOOP_EXPR
! 	  COMPOUND_EXPR
! 	    LABELED_BLOCK_EXPR
! 	      body
! 	    EXIT_EXPR
! 	      cond
  
      STMT is the statement to simplify.  */
  
  static void
! simplify_do_stmt (stmt_p)
!      tree *stmt_p;
  {
!   tree stmt = *stmt_p;
!   *stmt_p = simplify_c_loop (DO_COND (stmt), DO_BODY (stmt),
! 			     NULL_TREE, 0);
  }
  
  /*  Simplify an IF_STMT.  This will convert:
  
      	if (cond)
*************** simplify_do_stmt (stmt)
*** 732,769 ****
  	STMT should be stored.  */
  
  static void
! simplify_if_stmt (stmt, pre_p)
!      tree stmt;
!      tree *pre_p;
  {
!   tree cond_s;
! 
!   /* Make sure each clause is contained inside a scope.  */
!   if (THEN_CLAUSE (stmt))
!     tree_build_scope (&THEN_CLAUSE (stmt));
! 
!   if (ELSE_CLAUSE (stmt))
!     tree_build_scope (&ELSE_CLAUSE (stmt));
!       		
!   if (! is_simple_condexpr (IF_COND (stmt)))
!     {
!       /* Simplify the conditional.  */
!       cond_s = IF_COND (stmt);
!       walk_tree (&cond_s, mostly_copy_tree_r, NULL, NULL);
!       simplify_expr (&cond_s, pre_p, NULL, is_simple_condexpr,
! 		     fb_rvalue);
!       IF_COND (stmt) = cond_s;
!     }
! 
!   /* Simplify each of the clauses.  */
!   if (THEN_CLAUSE (stmt))
!     simplify_stmt (&THEN_CLAUSE (stmt));
  
!   if (ELSE_CLAUSE (stmt))
!     simplify_stmt (&ELSE_CLAUSE (stmt));
  }
  
- 
  /*  Simplify a SWITCH_STMT.  This will convert:
  
      	switch (cond)
--- 669,689 ----
  	STMT should be stored.  */
  
  static void
! simplify_if_stmt (stmt_p)
!      tree *stmt_p;
  {
!   tree stmt = *stmt_p;
!   tree then_ = THEN_CLAUSE (stmt);
!   tree else_ = ELSE_CLAUSE (stmt);
! 
!   c_simplify_stmt (&then_);
!   c_simplify_stmt (&else_);
!   if (else_ == NULL_TREE)
!     else_ = void_zero_node;
  
!   *stmt_p = build (COND_EXPR, void_type_node, IF_COND (stmt), then_, else_);
  }
  
  /*  Simplify a SWITCH_STMT.  This will convert:
  
      	switch (cond)
*************** simplify_if_stmt (stmt, pre_p)
*** 792,812 ****
  	STMT should be stored.  */
  
  static void
! simplify_switch_stmt (stmt, pre_p)
!      tree stmt;
!      tree *pre_p;
  {
!   if (!is_simple_val (SWITCH_COND (stmt)))
!     {
!       /* Simplify the conditional.  */
!       walk_tree (&SWITCH_COND (stmt), mostly_copy_tree_r, NULL, NULL);
!       simplify_expr (&SWITCH_COND (stmt), pre_p, NULL, is_simple_val,
! 		     fb_rvalue);
!     }
  
!   simplify_stmt (&SWITCH_BODY (stmt));
! }
  
  
  /*  Simplify a RETURN_STMT.  If the expression to be returned is not a
      SIMPLE value, it is assigned to a new temporary and the statement is
--- 712,734 ----
  	STMT should be stored.  */
  
  static void
! simplify_switch_stmt (stmt_p)
!      tree *stmt_p;
  {
!   tree stmt = *stmt_p;
!   tree body = SWITCH_BODY (stmt);
!   tree break_block, switch_;
  
!   break_block = begin_labeled_block (ctxp->break_id);
! 
!   c_simplify_stmt (&body);
! 
!   switch_ = build (SWITCH_EXPR, void_type_node, SWITCH_COND (stmt), body);
  
+   switch_ = finish_labeled_block (break_block, switch_);
+ 
+   *stmt_p = switch_;
+ }
  
  /*  Simplify a RETURN_STMT.  If the expression to be returned is not a
      SIMPLE value, it is assigned to a new temporary and the statement is
*************** simplify_switch_stmt (stmt, pre_p)
*** 816,826 ****
  	STMT should be stored.  */
  
  static void
! simplify_return_stmt (stmt, pre_p)
       tree stmt;
       tree *pre_p;
  {
!   tree ret_expr = RETURN_EXPR (stmt);
  
    if (ret_expr)
      {
--- 738,756 ----
  	STMT should be stored.  */
  
  static void
! simplify_return_stmt (stmt_p)
!      tree *stmt_p;
! {
!   tree stmt = *stmt_p;
!   *stmt_p = build (RETURN_EXPR, void_type_node, RETURN_STMT_EXPR (stmt));
! }
! 
! static void
! simplify_return_expr (stmt, pre_p)
       tree stmt;
       tree *pre_p;
  {
!   tree ret_expr = TREE_OPERAND (stmt, 0);
  
    if (ret_expr)
      {
*************** simplify_return_stmt (stmt, pre_p)
*** 828,837 ****
  	{
  	  /* We are trying to return an expression in a void function.
  	     Move the expression to before the return.  */
! 	  walk_tree (&ret_expr, mostly_copy_tree_r, NULL, NULL);
! 	  simplify_expr (&ret_expr, pre_p, NULL, is_simple_expr, fb_rvalue);
  	  add_tree (ret_expr, pre_p);
! 	  RETURN_EXPR (stmt) = NULL_TREE;
  	}
        else
  	{
--- 758,766 ----
  	{
  	  /* We are trying to return an expression in a void function.
  	     Move the expression to before the return.  */
! 	  simplify_stmt (&ret_expr);
  	  add_tree (ret_expr, pre_p);
! 	  TREE_OPERAND (stmt, 0) = NULL_TREE;
  	}
        else
  	{
*************** simplify_return_stmt (stmt, pre_p)
*** 874,922 ****
      different if the DECL_STMT is somehow embedded in an expression.  */
  
  static void
! simplify_decl_stmt (t, pre_p, mid_p, post_p)
!      tree t;
!      tree *pre_p;
!      tree *mid_p;
!      tree *post_p;
  {
!   tree decl, init, mid, post;
! 
! #if defined ENABLE_CHECKING
!   if (TREE_CODE (t) != DECL_STMT)
!     abort ();
! #endif
! 
!   if (is_simple_decl_stmt (t))
!     return;
  
!   /* We need to build these up internally first, in case mid_p and post_p
!      are the same.  */
!   mid = NULL_TREE;
!   post = NULL_TREE;
! 
!   decl = DECL_STMT_DECL (t);
!   init = DECL_INITIAL (decl);
!   DECL_INITIAL (decl) = NULL_TREE;
! 
!   if (DECL_SIZE_UNIT (decl)
!       && TREE_CODE (DECL_SIZE_UNIT (decl)) != INTEGER_CST)
!     {
!       walk_tree (&DECL_SIZE_UNIT (decl), mostly_copy_tree_r, NULL, NULL);
!       simplify_expr (&DECL_SIZE_UNIT (decl), pre_p, &post, is_simple_val,
! 		    fb_rvalue);
!     }
! 
!   if (init)
!     {
!       walk_tree (&init, mostly_copy_tree_r, NULL, NULL);
!       simplify_expr (&init, &mid, &post, is_simple_initializer, fb_rvalue);
!       init = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
!       add_tree (mid, mid_p);
!       add_tree (init, mid_p);
      }
! 
!   add_tree (post, post_p);
  }
  
  /* Simplifies a CONSTRUCTOR node T.
--- 803,822 ----
      different if the DECL_STMT is somehow embedded in an expression.  */
  
  static void
! simplify_decl_stmt (stmt_p)
!     tree *stmt_p;
  {
!   tree stmt = *stmt_p;
!   tree decl = DECL_STMT_DECL (stmt);
!   tree init = DECL_INITIAL (decl);
  
!   if (init && init != error_mark_node && !TREE_STATIC (decl))
!     {
!       DECL_INITIAL (decl) = NULL_TREE;
!       *stmt_p = build (INIT_EXPR, void_type_node, decl, init);
      }
!   else
!     *stmt_p = NULL_TREE;
  }
  
  /* Simplifies a CONSTRUCTOR node T.
*************** simplify_constructor (t, pre_p, post_p)
*** 946,963 ****
     instead.  */
  
  static void
! simplify_compound_literal_expr (expr_p, pre_p, post_p)
       tree *expr_p;
       tree *pre_p;
-      tree *post_p;
  {
    tree decl_s = COMPOUND_LITERAL_EXPR_DECL_STMT (*expr_p);
    tree decl = DECL_STMT_DECL (decl_s);
-   tree pre_init = NULL_TREE;
  
-   simplify_decl_stmt (decl_s, pre_p, &pre_init, post_p);
    add_tree (decl_s, pre_p);
-   add_tree (pre_init, pre_p);
    *expr_p = decl;
  }
  
--- 846,859 ----
     instead.  */
  
  static void
! simplify_compound_literal_expr (expr_p, pre_p)
       tree *expr_p;
       tree *pre_p;
  {
    tree decl_s = COMPOUND_LITERAL_EXPR_DECL_STMT (*expr_p);
    tree decl = DECL_STMT_DECL (decl_s);
  
    add_tree (decl_s, pre_p);
    *expr_p = decl;
  }
  
*************** simplify_expr (expr_p, pre_p, post_p, si
*** 1018,1023 ****
--- 914,921 ----
      {
        /* First do any language-specific simplification.  */
        (*lang_hooks.simplify_expr) (expr_p, pre_p, post_p);
+       if (*expr_p == NULL_TREE)
+ 	break;
  
        /* Then remember the expr.  */
        save_expr = *expr_p;
*************** simplify_expr (expr_p, pre_p, post_p, si
*** 1054,1060 ****
  	  break;
  
  	case COMPOUND_EXPR:
! 	  simplify_compound_expr (expr_p, pre_p, post_p);
  	  break;
  
  	case REALPART_EXPR:
--- 952,966 ----
  	  break;
  
  	case COMPOUND_EXPR:
! 	  if (is_statement)
! 	    {
! 	      tree link;
! 	      for (link = *expr_p; TREE_CODE (link) == COMPOUND_EXPR;
! 		   link = TREE_OPERAND (link, 1))
! 		simplify_stmt (&TREE_OPERAND (link, 0));
! 	    }
! 	  else
! 	    simplify_compound_expr (expr_p, pre_p, post_p);
  	  break;
  
  	case REALPART_EXPR:
*************** simplify_expr (expr_p, pre_p, post_p, si
*** 1110,1117 ****
  	  break;
  
  	case NEGATE_EXPR:
! 	  simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_simple_val,
! 			 fb_rvalue);
  	  break;
  
  	  /* Constants need not be simplified.  */
--- 1016,1023 ----
  	  break;
  
  	case NEGATE_EXPR:
! 	  simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			 is_simple_val, fb_rvalue);
  	  break;
  
  	  /* Constants need not be simplified.  */
*************** simplify_expr (expr_p, pre_p, post_p, si
*** 1121,1126 ****
--- 1027,1059 ----
  	case COMPLEX_CST:
  	  break;
  
+ 	case BIND_EXPR:
+ 	  simplify_stmt (&BIND_EXPR_BODY (*expr_p));
+ 	  break;
+ 
+ 	case LOOP_EXPR:
+ 	  simplify_stmt (&LOOP_EXPR_BODY (*expr_p));
+ 	  break;
+ 
+ 	case SWITCH_EXPR:
+ 	  simplify_expr (&SWITCH_EXPR_COND (*expr_p), pre_p, NULL,
+ 			 is_simple_val, fb_rvalue);
+ 	  simplify_stmt (&SWITCH_EXPR_BODY (*expr_p));
+ 	  break;
+ 
+ 	case LABELED_BLOCK_EXPR:
+ 	  simplify_stmt (&LABELED_BLOCK_BODY (*expr_p));
+ 	  break;
+ 
+ 	case EXIT_EXPR:
+ 	  simplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, NULL,
+ 			 is_simple_condexpr, fb_rvalue);
+ 	  break;
+ 
+ 	case RETURN_EXPR:
+ 	  simplify_return_expr (*expr_p, pre_p);
+ 	  break;
+ 
  	case CONSTRUCTOR:
  	  simplify_constructor (*expr_p, pre_p, post_p);
  	  break;
*************** simplify_expr (expr_p, pre_p, post_p, si
*** 1181,1199 ****
  	}
      }
    /* If we replaced *expr_p, simplify again.  */
!   while (*expr_p != save_expr);
  
    /* If we are simplifying at the statement level, we're done.  Tack
       everything together and replace the original statement with the
       simplified form.  */
    if (is_statement)
      {
- #if 0
-       /* Soon.  */
        add_tree (*expr_p, pre_p);
        add_tree (internal_post, pre_p);
!       *expr_p = rationalize_compound_expr (internal_pre);
! #endif
        return 1;
      }
  
--- 1114,1132 ----
  	}
      }
    /* If we replaced *expr_p, simplify again.  */
!   while (*expr_p && *expr_p != save_expr);
  
    /* If we are simplifying at the statement level, we're done.  Tack
       everything together and replace the original statement with the
       simplified form.  */
    if (is_statement)
      {
        add_tree (*expr_p, pre_p);
        add_tree (internal_post, pre_p);
!       tmp = rationalize_compound_expr (internal_pre);
!       if (tmp == NULL_TREE)
! 	tmp = void_zero_node;
!       *expr_p = tmp;
        return 1;
      }
  
*************** int
*** 1259,1277 ****
  c_simplify_expr (expr_p, pre_p, post_p)
       tree *expr_p;
       tree *pre_p;
!      tree *post_p;
  {
    enum tree_code code = TREE_CODE (*expr_p);
    
    if (statement_code_p (code))
      {
!       simplify_stmt (expr_p);
        return 1;
      }
    else switch (code)
      {
      case COMPOUND_LITERAL_EXPR:
!       simplify_compound_literal_expr (expr_p, pre_p, post_p);
        return 1;
  
      case STMT_EXPR:
--- 1192,1212 ----
  c_simplify_expr (expr_p, pre_p, post_p)
       tree *expr_p;
       tree *pre_p;
!      tree *post_p ATTRIBUTE_UNUSED;
  {
    enum tree_code code = TREE_CODE (*expr_p);
    
    if (statement_code_p (code))
      {
!       push_context ();
!       c_simplify_stmt (expr_p);
!       pop_context ();
        return 1;
      }
    else switch (code)
      {
      case COMPOUND_LITERAL_EXPR:
!       simplify_compound_literal_expr (expr_p, pre_p);
        return 1;
  
      case STMT_EXPR:
*************** simplify_cond_expr (expr_p, pre_p)
*** 1612,1640 ****
    if (!VOID_TYPE_P (expr_type))
      tmp = create_tmp_var (TREE_TYPE (*expr_p), "iftmp");
    else
!     tmp = void_zero_node;
  
    pred = TREE_OPERAND (*expr_p, 0);
    tval = TREE_OPERAND (*expr_p, 1);
    fval = TREE_OPERAND (*expr_p, 2);
  
    /* Build the THEN_CLAUSE 't1 = a;' or 'a;'.  */
!   if (!VOID_TYPE_P (expr_type))
!     t_then = build_stmt (EXPR_STMT, build_modify_expr (tmp, NOP_EXPR, tval));
    else
!     t_then = build_stmt (EXPR_STMT, tval);
!   tree_build_scope (&t_then);
  
    /* Build the ELSE_CLAUSE 't1 = b;' or 'b;'.  */
!   if (!VOID_TYPE_P (expr_type))
!     t_else = build_stmt (EXPR_STMT, build_modify_expr (tmp, NOP_EXPR, fval));
    else
!     t_else = build_stmt (EXPR_STMT, fval);
!   tree_build_scope (&t_else);
  
    /* Build a new IF_STMT, simplify it and insert it in the PRE_P chain.  */
!   new_if = build_stmt (IF_STMT, pred, t_then, t_else);
!   simplify_if_stmt (new_if, pre_p);
    add_tree (new_if, pre_p);
  
    /* Replace the original expression with the new temporary.  */
--- 1547,1576 ----
    if (!VOID_TYPE_P (expr_type))
      tmp = create_tmp_var (TREE_TYPE (*expr_p), "iftmp");
    else
!     tmp = NULL_TREE;
  
    pred = TREE_OPERAND (*expr_p, 0);
    tval = TREE_OPERAND (*expr_p, 1);
    fval = TREE_OPERAND (*expr_p, 2);
  
    /* Build the THEN_CLAUSE 't1 = a;' or 'a;'.  */
!   if (tmp)
!     t_then = build_modify_expr (tmp, NOP_EXPR, tval);
    else
!     t_then = tval;
  
    /* Build the ELSE_CLAUSE 't1 = b;' or 'b;'.  */
!   if (tmp)
!     t_else = build_modify_expr (tmp, NOP_EXPR, fval);
    else
!     t_else = fval;
! 
!   simplify_expr (&pred, pre_p, NULL, is_simple_condexpr, fb_rvalue);
!   simplify_stmt (&t_then);
!   simplify_stmt (&t_else);
  
    /* Build a new IF_STMT, simplify it and insert it in the PRE_P chain.  */
!   new_if = build (COND_EXPR, void_type_node, pred, t_then, t_else);
    add_tree (new_if, pre_p);
  
    /* Replace the original expression with the new temporary.  */
*************** simplify_boolean_expr (expr_p, pre_p)
*** 1722,1729 ****
       RHS of the expression.  Note that we first build the assignment
       surrounded by a new scope so that its simplified form is computed
       inside the new scope.  */
!   if_body = build_stmt (EXPR_STMT, build_modify_expr (t, NOP_EXPR, rhs));
!   tree_build_scope (&if_body);
  
    /* Build the statement 'if (T = a <comp> 0) T = b;'.  Where <comp> is
       NE_EXPR if we are processing && and EQ_EXPR if we are processing ||.
--- 1658,1664 ----
       RHS of the expression.  Note that we first build the assignment
       surrounded by a new scope so that its simplified form is computed
       inside the new scope.  */
!   if_body = build_modify_expr (t, NOP_EXPR, rhs);
  
    /* Build the statement 'if (T = a <comp> 0) T = b;'.  Where <comp> is
       NE_EXPR if we are processing && and EQ_EXPR if we are processing ||.
*************** simplify_boolean_expr (expr_p, pre_p)
*** 1737,1754 ****
    else
      if_cond = build (EQ_EXPR, TREE_TYPE (t), t, integer_zero_node);
  
!   if_stmt = build_stmt (IF_STMT, if_cond, if_body, NULL_TREE);
  
    /* Simplify the IF_STMT and insert it in the PRE_P chain.  */
-   simplify_if_stmt (if_stmt, pre_p);
    add_tree (if_stmt, pre_p);
  
    /* If we're not actually looking for a boolean result, convert now.  */
    if (TREE_TYPE (t) != TREE_TYPE (*expr_p))
!     {
!       t = convert (TREE_TYPE (*expr_p), t);
!       simplify_expr (&t, pre_p, NULL, is_simple_id, fb_rvalue);
!     }
  
    /* Re-write the original expression to use T.  */
    *expr_p = t;
--- 1672,1686 ----
    else
      if_cond = build (EQ_EXPR, TREE_TYPE (t), t, integer_zero_node);
  
!   if_stmt = build (COND_EXPR, void_type_node, if_cond, if_body, void_zero_node);
!   simplify_stmt (&if_stmt);
  
    /* Simplify the IF_STMT and insert it in the PRE_P chain.  */
    add_tree (if_stmt, pre_p);
  
    /* If we're not actually looking for a boolean result, convert now.  */
    if (TREE_TYPE (t) != TREE_TYPE (*expr_p))
!      t = convert (TREE_TYPE (*expr_p), t);
  
    /* Re-write the original expression to use T.  */
    *expr_p = t;
*************** simplify_stmt_expr (expr_p, pre_p)
*** 1988,1998 ****
  	    last_expr_stmt = substmt;
  	}
  
- #if defined ENABLE_CHECKING
-       if (!last_expr_stmt)
- 	abort ();
- #endif
- 
        last_expr = EXPR_STMT_EXPR (last_expr_stmt);
  
        if (TREE_CHAIN (last_expr_stmt) == NULL_TREE
--- 1920,1925 ----
*************** tree_build_scope (t)
*** 2093,2098 ****
--- 2020,2039 ----
    *t = comp_stmt;
  }
  
+ /* Add STMT to EXISTING if possible, otherwise create a new
+    COMPOUND_EXPR and add STMT to it. */
+ 
+ static tree
+ add_stmt_to_compound (existing, stmt)
+      tree existing, stmt;
+ {
+   if (!stmt || !expr_has_effect (stmt))
+     return existing;
+   else if (existing)
+     return build (COMPOUND_EXPR, void_type_node, existing, stmt);
+   else
+     return stmt;
+ }
  
  /*  Add T to the list container pointed by LIST_P.  If T is a TREE_LIST
      node, it is linked-in directly.  If T is an expression with no effects,
*************** add_tree (t, list_p)
*** 2106,2239 ****
      tree t;
      tree *list_p;
  {
!   if (t == NULL_TREE)
      return NULL_TREE;
  
!   /* Do nothing if T has no effect.  */
!   if (statement_code_p (TREE_CODE (t)))
!     {
!       if (!stmt_has_effect (t))
! 	return NULL_TREE;
!     }
!   else
!     {
!       if (!expr_has_effect (t))
! 	return NULL_TREE;
!       t = build_stmt (EXPR_STMT, t);
!     }
! 
!   *list_p = chainon (*list_p, t);
! 
    return t;
  }
  
  
- /*  Insert the REEVAL list before CONTINUE_STMTs and at the end of the loop
-     body BODY.  Set the line number of the REEVAL list to LINE.  */
- 
- void
- insert_before_continue_end (reeval, body)
-      tree reeval;
-      tree body;
- {
-   tree last, beforelast;
- 
-   if (reeval == NULL_TREE)
-     return;
- 
-   /* Make sure that the loop body has a scope.  */
-   tree_build_scope (&body);
- 
-   /* Insert the reevaluation list before every CONTINUE_STMT.  */
-   /*  TREE_CHAIN (reeval) = NULL_TREE; */
-   beforelast = insert_before_continue (body, reeval);
-   last = TREE_CHAIN (beforelast);
-   
-   /* If the last statement of the WHILE_BODY is not a CONTINUE_STMT, 
-      then insert reeval at the end of the loop block.  */
-   if (TREE_CODE (beforelast) != CONTINUE_STMT)
-     {
-       TREE_CHAIN (beforelast) = deep_copy_list (reeval);
-       beforelast = tree_last (beforelast);
-       TREE_CHAIN (beforelast) = last;
-     }
- }
- 
- 
- /*  Insert the statement list REEVAL before each CONTINUE_STMT in the block
-     pointed to by NODE.  At the end returns a pointer to the beforelast
-     node in the block NODE.  The caller can insert then the last loop
-     reevaluation at the end of the loop block.  */
- 
- static tree
- insert_before_continue (node, reeval)
-      tree node;
-      tree reeval;
- {
-   tree next;
- 
-   if (reeval == NULL_TREE || node == NULL_TREE)
-     return NULL_TREE;
-   
-   if (TREE_CODE (node) == COMPOUND_STMT)
-     node = COMPOUND_BODY (node);
-   
-   next = TREE_CHAIN (node);
-   if (next == NULL_TREE)
-     return NULL_TREE;
- 
-   /* Walk through each statement in the given block up to the last one, 
-      searching for CONTINUE_STMTs.  */
-   for ( ;TREE_CHAIN (next) != NULL_TREE; 
- 	node = TREE_CHAIN (node), next = TREE_CHAIN (next))
-     {
-       switch (TREE_CODE (next))
- 	{
- 	case CONTINUE_STMT:
- 	  /* Insert the reeval of statements before continue.  */
- 	  TREE_CHAIN (node) = deep_copy_list (reeval);
- 	  node = tree_last (node);
- 	  TREE_CHAIN (node) = next;
- 	  break;
- 	  
- 	case IF_STMT:
- 	  /* Be sure that the THEN_CLAUSE has a scope.  */
- 	  tree_build_scope (&THEN_CLAUSE (next));
- 
- 	  /* Insert the code REEVAL in the block of the THEN_CLAUSE.  */
- 	  insert_before_continue (COMPOUND_BODY (THEN_CLAUSE (next)), reeval);
- 	  
- 	  /* Same thing for the ELSE_CLAUSE.  */
- 	  if (ELSE_CLAUSE (TREE_CHAIN (node)))
- 	    {
- 	      tree_build_scope (&ELSE_CLAUSE (next));
- 	      insert_before_continue (COMPOUND_BODY (ELSE_CLAUSE (next)), reeval);
- 	    }
- 	  break;
- 
- 	case SWITCH_STMT:
- 	  /* Be sure that the SWITCH_BODY has a scope.  */
- 	  tree_build_scope (&SWITCH_BODY (next));
- 
- 	  /* Insert the code REEVAL in the SWITCH_BODY.  */
- 	  insert_before_continue (COMPOUND_BODY (SWITCH_BODY (next)), reeval);
- 	  break;
- 
- 	case COMPOUND_STMT:
- 	  /* Insert in the inner block.  */
- 	  insert_before_continue (COMPOUND_BODY (next), reeval);
- 	  break;
- 
- 	default:
- 	  /* Don't enter in sub loops...  The continue statement has an effect 
- 	     only at a depth 1.  */
- 	  break;
- 	}
-     }
-   return node;
- }
- 
- 
  /* Miscellaneous helpers.  */
  
  /*  Create a new temporary variable declaration of type TYPE.  Returns the
--- 2047,2060 ----
      tree t;
      tree *list_p;
  {
!   if (t == NULL_TREE || !expr_has_effect (t))
      return NULL_TREE;
  
!   *list_p = add_stmt_to_compound (*list_p, t);
    return t;
  }
  
  
  /* Miscellaneous helpers.  */
  
  /*  Create a new temporary variable declaration of type TYPE.  Returns the
*************** declare_tmp_vars (vars, scope)
*** 2442,2497 ****
       tree vars;
       tree scope;
  {
!   tree t, last;
! 
!   /* Find the last declaration statement in the scope.  Add all the new
!      declarations after it.  */
!   last = tree_last_decl (scope);
! 
!   for (t = vars; t; t = TREE_CHAIN (t))
!     {
!       tree decl, tmp;
! 
!       decl = build_stmt (DECL_STMT, t);
!       STMT_LINENO (decl) = STMT_LINENO (scope);
! 
!       tmp = TREE_CHAIN (last);
!       TREE_CHAIN (last) = decl;
!       TREE_CHAIN (decl) = tmp;
! 
!       last = decl;
!     }
! 
!   return last;
! }
! 
! 
! /*  Returns the last DECL_STMT in the scope SCOPE.  */
! 
! static tree
! tree_last_decl (scope)
!      tree scope;
! {
!   tree last;
! 
!   /* Be sure that we get a scope.  Ignore FILE_STMT nodes.  */
!   while (TREE_CODE (scope) == FILE_STMT)
!     scope = TREE_CHAIN (scope);
! 
! #if defined ENABLE_CHECKING
!   /* In C99 mode, we can find DECL_STMT nodes before the body of the
!      function.  In that case, we declare all the temporaries there.  */
!   if (TREE_CODE (scope) != DECL_STMT
!       && !SCOPE_BEGIN_P (scope))
      abort ();
- #endif
  
!   /* Find the last declaration statement in the scope.  */
!   last = scope;
!   while (TREE_CHAIN (last) && TREE_CODE (TREE_CHAIN (last)) == DECL_STMT)
!     last = TREE_CHAIN (last);
  
!   return last;
  }
  
  
--- 2263,2274 ----
       tree vars;
       tree scope;
  {
!   if (TREE_CODE (scope) != BIND_EXPR)
      abort ();
  
!   BIND_EXPR_VARS (scope) = chainon (BIND_EXPR_VARS (scope), vars);
  
!   return NULL_TREE;
  }
  
  
*************** deep_copy_node (node)
*** 2582,2588 ****
        break;
  
      case RETURN_STMT:
!       res = build_stmt (RETURN_STMT, deep_copy_node (RETURN_EXPR (node)));
        break;
  
      case TREE_LIST:
--- 2359,2365 ----
        break;
  
      case RETURN_STMT:
!       res = build_stmt (RETURN_STMT, deep_copy_node (RETURN_STMT_EXPR (node)));
        break;
  
      case TREE_LIST:
*************** deep_copy_node (node)
*** 2619,2640 ****
    return res;
  }
  
- /*  Return nonzero if STMT has some effect (i.e., if it's not of the form
-     'a;' where a is a non-volatile variable).  */
-     
- static int
- stmt_has_effect (stmt)
-      tree stmt;
- {
-   if (TREE_CODE (stmt) != EXPR_STMT)
-     return 1;
-   else if (expr_has_effect (EXPR_STMT_EXPR (stmt)))
-     return 1;
- 
-   return 0;
- }
- 
- 
  /*  Return nonzero if EXPR has some effect (e.g., it's not a single
      non-volatile VAR_DECL).  */
  
--- 2396,2401 ----
*************** is_last_stmt_of_scope (stmt)
*** 2698,2746 ****
  	  && SCOPE_END_P (TREE_CHAIN (stmt)));
  }
  
- /* If the last entry in CHAIN is an expression, return it; otherwise,
-    return NULL_TREE.
- 
-    If DECL_IS_BAD is nonzero, seeing a DECL_STMT causes us to bail out to
-    avoid scoping problems.  */
- 
- static tree
- tail_expression (chain, decl_is_bad)
-      tree *chain;
-      int decl_is_bad;
- {
-   if (*chain)
-     {
-       tree *first_expr = 0;
- 
-       for (; *chain; chain = &TREE_CHAIN (*chain))
- 	{
- 	  tree elt = *chain;
- 	  if (TREE_CODE (elt) == EXPR_STMT)
- 	    first_expr = chain;
- 	  else
- 	    {
- 	      if (decl_is_bad && (TREE_CODE (elt) == DECL_STMT))
- 		return NULL_TREE;
- 	      first_expr = 0;
- 	    }
- 	}
- 
-       if (first_expr)
- 	{
- 	  tree exprs = nreverse (*first_expr);
- 	  tree compexpr = EXPR_STMT_EXPR (exprs);
- 	  for (exprs = TREE_CHAIN (exprs); exprs; exprs = TREE_CHAIN (exprs))
- 	    compexpr = build (COMPOUND_EXPR, TREE_TYPE (compexpr),
- 			      EXPR_STMT_EXPR (exprs), compexpr);
- 	  *first_expr = 0;
- 	  return compexpr;
- 	}
-     }
-   return NULL_TREE;
- }
- 
- 
  /* Returns nonzero if STMT is a SIMPLE declaration, i.e. one with no
     initializer.
  
--- 2459,2464 ----
*** ./expr.c.~1~	Tue Aug 20 14:31:04 2002
--- ./expr.c	Thu Aug 22 23:06:53 2002
*************** expand_expr (exp, target, tmode, modifie
*** 6699,6705 ****
  
      case LOOP_EXPR:
        push_temp_slots ();
!       expand_start_loop (1);
        expand_expr_stmt_value (TREE_OPERAND (exp, 0), 0, 1);
        expand_end_loop ();
        pop_temp_slots ();
--- 6699,6705 ----
  
      case LOOP_EXPR:
        push_temp_slots ();
!       expand_start_loop (0);
        expand_expr_stmt_value (TREE_OPERAND (exp, 0), 0, 1);
        expand_end_loop ();
        pop_temp_slots ();
*************** expand_expr (exp, target, tmode, modifie
*** 9029,9034 ****
--- 9029,9067 ----
  	 initialization constants, and should not be expanded.  */
        abort ();
  
+     case SWITCH_EXPR:
+       expand_start_case (0, SWITCH_EXPR_COND (exp), integer_type_node,
+ 			 "switch");
+       expand_expr_stmt (SWITCH_EXPR_BODY (exp));
+       expand_end_case (SWITCH_EXPR_COND (exp));
+       return const0_rtx;
+ 
+     case LABEL_EXPR:
+       expand_label (TREE_OPERAND (exp, 0));
+       return const0_rtx;
+ 
+     case CASE_LABEL_EXPR:
+       {
+ 	tree duplicate;
+ 	add_case_node (CASE_LABEL_EXPR_LOW (exp), CASE_LABEL_EXPR_HIGH (exp),
+ 		       build_decl (LABEL_DECL, NULL_TREE, NULL_TREE), 
+ 		       &duplicate);
+ 	if (duplicate)
+ 	  abort ();
+ 	return const0_rtx;
+       }
+ 
+     case ASM_EXPR:
+       if (ASM_EXPR_INPUT_P (exp))
+ 	expand_asm (ASM_EXPR_STRING (exp));
+       else
+ 	expand_asm_operands (ASM_EXPR_STRING (exp), ASM_EXPR_OUTPUTS (exp),
+ 			     ASM_EXPR_INPUTS (exp), ASM_EXPR_CLOBBERS (exp),
+ 			     ASM_EXPR_CV_QUAL (exp) != NULL_TREE,
+ 			     input_filename, lineno);
+       /* FIXME copy outputs into proper locations?  */
+       return const0_rtx;
+ 
      default:
        return (*lang_hooks.expand_expr) (exp, original_target, tmode, modifier);
      }
*** ./java/expr.c.~1~	Tue Aug 20 14:22:44 2002
--- ./java/expr.c	Thu Aug 22 23:07:31 2002
*************** java_expand_expr (exp, target, tmode, mo
*** 2596,2607 ****
  		build_decl (LABEL_DECL, NULL_TREE, NULL_TREE), NULL);
        return const0_rtx;
  
-     case SWITCH_EXPR:
-       expand_start_case (0, TREE_OPERAND (exp, 0), int_type_node, "switch");
-       expand_expr_stmt (TREE_OPERAND (exp, 1));
-       expand_end_case (TREE_OPERAND (exp, 0));
-       return const0_rtx;
- 
      case TRY_EXPR:
        /* We expand a try[-catch] block */
  
--- 2596,2601 ----
*************** java_expand_expr (exp, target, tmode, mo
*** 2629,2639 ****
        return expand_expr (build_exception_object_ref (TREE_TYPE (exp)),
  			  target, tmode, modifier);
  
-     case LABEL_EXPR:
-       /* Used only by expanded inline functions.  */
-       expand_label (TREE_OPERAND (exp, 0));
-       return const0_rtx;
- 
      default:
        internal_error ("can't expand %s", tree_code_name [TREE_CODE (exp)]);
      }
--- 2623,2628 ----
*** ./tree-simple.h.~1~	Tue Aug 20 14:31:04 2002
--- ./tree-simple.h	Wed Aug 21 10:39:06 2002
*************** extern tree declare_tmp_vars           P
*** 33,38 ****
--- 33,39 ----
  extern tree deep_copy_list             PARAMS ((tree));
  extern tree deep_copy_node             PARAMS ((tree));
  extern tree update_line_number         PARAMS ((tree, int));
+ extern tree rationalize_compound_expr  PARAMS ((tree));
  
  /* Validation of SIMPLE expressions.  */
  int is_simple_expr                     PARAMS ((tree));
*************** int is_simple_initializer              P
*** 63,68 ****
--- 64,81 ----
  int is_simplifiable_builtin            PARAMS ((tree));
  int is_simple_decl_stmt                PARAMS ((tree));
  
+ typedef struct simplify_ctx
+ {
+   /* PRE_P points to the list for side effects that must happen before
+      the current expression is evaluated.  */
+   tree *pre_p;
+   /* POST_P points to the list for side effects that must happen after
+      the current expression is evaluated.  */
+   tree *post_p;
+   /* DECL_SCOPE points to the BIND_EXPR for the current scope.  */
+   tree decl_scope;
+ } simplify_ctx;
+ 
  /* FIXME this needs a better name.  */
  tree add_tree			       PARAMS ((tree, tree *));
  /* FIXME we should deduce this from the predicate.  */
*************** int simplify_expr		       PARAMS ((tree 
*** 75,80 ****
--- 88,96 ----
  						int (*) PARAMS ((tree)),
  						fallback_t));
  
+ #define simplify_stmt(EXPR_P) \
+   simplify_expr ((EXPR_P), NULL, NULL, NULL, fb_rvalue);
+ 
  /* Miscellaneous helpers.  */
  tree get_base_symbol                   PARAMS ((tree));
  
*** ./tree.def.~1~	Tue Aug 20 14:31:04 2002
--- ./tree.def	Thu Aug 22 16:13:41 2002
*************** DEFTREECODE (TARGET_EXPR, "target_expr",
*** 443,452 ****
  DEFTREECODE (COND_EXPR, "cond_expr", 'e', 3)
  
  /* Declare local variables, including making RTL and allocating space.
!    Operand 0 is a chain of VAR_DECL nodes for the variables.
!    Operand 1 is the body, the expression to be computed using 
     the variables.  The value of operand 1 becomes that of the BIND_EXPR.
!    Operand 2 is the BLOCK that corresponds to these bindings
     for debugging purposes.  If this BIND_EXPR is actually expanded,
     that sets the TREE_USED flag in the BLOCK.
  
--- 443,452 ----
  DEFTREECODE (COND_EXPR, "cond_expr", 'e', 3)
  
  /* Declare local variables, including making RTL and allocating space.
!    BIND_EXPR_VARS is a chain of VAR_DECL nodes for the variables.
!    BIND_EXPR_BODY is the body, the expression to be computed using 
     the variables.  The value of operand 1 becomes that of the BIND_EXPR.
!    BIND_EXPR_BLOCK is the BLOCK that corresponds to these bindings
     for debugging purposes.  If this BIND_EXPR is actually expanded,
     that sets the TREE_USED flag in the BLOCK.
  
*************** DEFTREECODE (VA_ARG_EXPR, "va_arg_expr",
*** 771,778 ****
  /* Evaluate operand 1.  If and only if an exception is thrown during
     the evaluation of operand 1, evaluate operand 2.
  
!    This differs from WITH_CLEANUP_EXPR, in that operand 2 is never
!    evaluated unless an exception is throw.  */
  DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", 'e', 2)
  
  /* Evaluate the first operand.
--- 771,778 ----
  /* Evaluate operand 1.  If and only if an exception is thrown during
     the evaluation of operand 1, evaluate operand 2.
  
!    This differs from TRY_FINALLY_EXPR in that operand 2 is not evaluated
!    on a normal or jump exit, only on an exception.  */
  DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", 'e', 2)
  
  /* Evaluate the first operand.
*************** DEFTREECODE (EXPR_WITH_FILE_LOCATION, "e
*** 845,857 ****
  
  /* Switch expression.
     Operand 0 is the expression used to perform the branch,
!    Operand 1 contains the case values. The way they're organized is
!    front-end implementation defined. */
  DEFTREECODE (SWITCH_EXPR, "switch_expr", 'e', 2)
  
  /* The exception object from the runtime.  */
  DEFTREECODE (EXC_PTR_EXPR, "exc_ptr_expr", 'e', 0)
  
  /*
  Local variables:
  mode:c
--- 845,867 ----
  
  /* Switch expression.
     Operand 0 is the expression used to perform the branch,
!    Operand 1 is the body of the switch, which probably contains CASE_LABEL_EXPRs. */
  DEFTREECODE (SWITCH_EXPR, "switch_expr", 'e', 2)
  
+ /* Used to represent a case label. The operands are CASE_LOW and
+    CASE_HIGH, respectively. If CASE_LOW is NULL_TREE, the label is a
+    'default' label. If CASE_HIGH is NULL_TREE, the label is a normal case
+    label.  */
+ DEFTREECODE (CASE_LABEL_EXPR, "case_label_expr", 'e', 2)
+ 
  /* The exception object from the runtime.  */
  DEFTREECODE (EXC_PTR_EXPR, "exc_ptr_expr", 'e', 0)
  
+ /* Used to represent an inline assembly statement.  ASM_STRING returns a
+    STRING_CST for the instruction (e.g., "mov x, y"). ASM_OUTPUTS,
+    ASM_INPUTS, and ASM_CLOBBERS represent the outputs, inputs, and clobbers
+    for the statement.  */
+ DEFTREECODE (ASM_EXPR, "asm_expr", 'e', 1)
  /*
  Local variables:
  mode:c
*** ./tree.h.~1~	Tue Aug 20 14:31:04 2002
--- ./tree.h	Wed Aug 21 11:17:30 2002
*************** struct tree_vec GTY(())
*** 885,890 ****
--- 885,913 ----
  #define TARGET_EXPR_INITIAL(NODE) TREE_OPERAND (TARGET_EXPR_CHECK (NODE), 1)
  #define TARGET_EXPR_CLEANUP(NODE) TREE_OPERAND (TARGET_EXPR_CHECK (NODE), 2)
  
+ /* ASM_EXPR accessors. ASM_STRING returns a STRING_CST for the
+    instruction (e.g., "mov x, y"). ASM_OUTPUTS, ASM_INPUTS, and
+    ASM_CLOBBERS represent the outputs, inputs, and clobbers for the
+    statement.  */
+ #define ASM_EXPR_CV_QUAL(NODE)       TREE_OPERAND (ASM_EXPR_CHECK (NODE), 0)
+ #define ASM_EXPR_STRING(NODE)        TREE_OPERAND (ASM_EXPR_CHECK (NODE), 1)
+ #define ASM_EXPR_OUTPUTS(NODE)       TREE_OPERAND (ASM_EXPR_CHECK (NODE), 2)
+ #define ASM_EXPR_INPUTS(NODE)        TREE_OPERAND (ASM_EXPR_CHECK (NODE), 3)
+ #define ASM_EXPR_CLOBBERS(NODE)      TREE_OPERAND (ASM_EXPR_CHECK (NODE), 4)
+ /* Nonzero if we want to create an ASM_INPUT instead of an
+    ASM_OPERAND with no operands.  */
+ #define ASM_EXPR_INPUT_P(NODE) (TREE_LANG_FLAG_0 (NODE))
+ 
+ /* SWITCH_EXPR accessors. These give access to the condition and body
+    of the switch statement, respectively.  */
+ #define SWITCH_EXPR_COND(NODE)       TREE_OPERAND (SWITCH_EXPR_CHECK (NODE), 0)
+ #define SWITCH_EXPR_BODY(NODE)       TREE_OPERAND (SWITCH_EXPR_CHECK (NODE), 1)
+ 
+ /* CASE_LABEL_EXPR accessors. These give access to the high and low values
+    of a case label, respectively.  */
+ #define CASE_LABEL_EXPR_LOW(NODE) TREE_OPERAND (CASE_LABEL_EXPR_CHECK (NODE), 0)
+ #define CASE_LABEL_EXPR_HIGH(NODE) TREE_OPERAND (CASE_LABEL_EXPR_CHECK (NODE), 1)
+ 
  struct tree_exp GTY(())
  {
    struct tree_common common;
*************** struct tree_exp GTY(())
*** 894,899 ****
--- 917,927 ----
      operands[1];
  };
  
+ /* The operands of a BIND_EXPR.  */
+ #define BIND_EXPR_VARS(NODE) (TREE_OPERAND (BIND_EXPR_CHECK (NODE), 0))
+ #define BIND_EXPR_BODY(NODE) (TREE_OPERAND (BIND_EXPR_CHECK (NODE), 1))
+ #define BIND_EXPR_BLOCK(NODE) (TREE_OPERAND (BIND_EXPR_CHECK (NODE), 2))
+ 
  /* In a BLOCK node.  */
  #define BLOCK_VARS(NODE) (BLOCK_CHECK (NODE)->block.vars)
  #define BLOCK_SUBBLOCKS(NODE) (BLOCK_CHECK (NODE)->block.subblocks)
*************** extern void gcc_obstack_init		PARAMS ((s
*** 2896,2901 ****
--- 2924,2930 ----
  extern void init_ttree			PARAMS ((void));
  extern void build_common_tree_nodes	PARAMS ((int));
  extern void build_common_tree_nodes_2	PARAMS ((int));
+ extern tree add_to_compound_expr	PARAMS ((tree, tree));
  
  /* In function.c */
  extern void setjmp_protect_args		PARAMS ((void));
*** ./tree.c.~1~	Mon Aug 12 03:14:15 2002
--- ./tree.c	Thu Aug 22 14:37:29 2002
*************** tree
*** 1023,1029 ****
  chainon (op1, op2)
       tree op1, op2;
  {
- 
    if (op1)
      {
        tree t1;
--- 1023,1028 ----
*************** initializer_zerop (init)
*** 4853,4856 ****
--- 4852,4870 ----
      }
  }
  
+ /* Add STMT to EXISTING if possible, otherwise create a new
+    COMPOUND_EXPR and add STMT to it. */
+ 
+ tree
+ add_stmt_to_compound (existing, type, stmt)
+      tree existing, type, stmt;
+ {
+   if (!stmt)
+     return existing;
+   else if (existing)
+     return build (COMPOUND_EXPR, type, existing, stmt);
+   else
+     return stmt;
+ }
+ 
  #include "gt-tree.h"
*** ./c-dump.c.~1~	Wed Jul 31 19:07:16 2002
--- ./c-dump.c	Wed Aug 21 12:46:51 2002
*************** c_dump_tree (dump_info, t)
*** 153,159 ****
  
      case RETURN_STMT:
        dump_stmt (di, t);
!       dump_child ("expr", RETURN_EXPR (t));
        dump_next_stmt (di, t);
        break;
  
--- 153,159 ----
  
      case RETURN_STMT:
        dump_stmt (di, t);
!       dump_child ("expr", RETURN_STMT_EXPR (t));
        dump_next_stmt (di, t);
        break;
  
*** ./tree-simple.c.~1~	Tue Aug 20 14:21:23 2002
--- ./tree-simple.c	Wed Aug 21 12:51:51 2002
*************** rationalize_compound_expr (top)
*** 912,938 ****
       tree top;
  {
    tree cur = top;
!   while (TREE_CODE (cur) == COMPOUND_EXPR)
!     {
!       tree lhs = TREE_OPERAND (cur, 0);
!       tree rhs = TREE_OPERAND (cur, 1);
!       if (TREE_CODE (lhs) == COMPOUND_EXPR)
! 	{
! 	  /* We have ((a, b), c).  Rearrange to (a, (b, c)).  */
! 	  tree lhs1 = TREE_OPERAND (lhs, 0);
! 	  tree rhs1 = TREE_OPERAND (lhs, 1);
! 
! 	  /* Change lhs from (a, b) to (b, c).  */
! 	  TREE_OPERAND (lhs, 0) = rhs1;
! 	  TREE_OPERAND (lhs, 1) = rhs;
! 
! 	  /* Change cur from (lhs, c) to (a, lhs), i.e. (a, (b, c)).  */
! 	  TREE_OPERAND (cur, 0) = lhs1;
! 	  TREE_OPERAND (cur, 1) = lhs;
! 	}
!       else
! 	cur = rhs;
!     }
    return top;
  }
  
--- 912,939 ----
       tree top;
  {
    tree cur = top;
!   if (cur)
!     while (TREE_CODE (cur) == COMPOUND_EXPR)
!       {
! 	tree lhs = TREE_OPERAND (cur, 0);
! 	tree rhs = TREE_OPERAND (cur, 1);
! 	if (TREE_CODE (lhs) == COMPOUND_EXPR)
! 	  {
! 	    /* We have ((a, b), c).  Rearrange to (a, (b, c)).  */
! 	    tree lhs1 = TREE_OPERAND (lhs, 0);
! 	    tree rhs1 = TREE_OPERAND (lhs, 1);
! 
! 	    /* Change lhs from (a, b) to (b, c).  */
! 	    TREE_OPERAND (lhs, 0) = rhs1;
! 	    TREE_OPERAND (lhs, 1) = rhs;
! 
! 	    /* Change cur from (lhs, c) to (a, lhs), i.e. (a, (b, c)).  */
! 	    TREE_OPERAND (cur, 0) = lhs1;
! 	    TREE_OPERAND (cur, 1) = lhs;
! 	  }
! 	else
! 	  cur = rhs;
!       }
    return top;
  }
  
*************** get_base_symbol (t)
*** 964,966 ****
--- 965,1010 ----
      }
  }
  
+ #if 0
+ void
+ simplify_return_expr (expr_p, pre_p)
+      tree *expr_p;
+      tree *pre_p;
+ {
+   tree ret_expr = TREE_OPERAND (*expr_p, 0);
+ 
+   if (ret_expr)
+     {
+       if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
+ 	{
+ 	  /* We are trying to return an expression in a void function.
+ 	     Move the expression to before the return.  */
+ 	  walk_tree (&ret_expr, mostly_copy_tree_r, NULL, NULL);
+ 	  simplify_expr (&ret_expr, pre_p, NULL, is_simple_expr, fb_rvalue);
+ 	  add_tree (ret_expr, pre_p);
+ 	  RETURN_STMT_EXPR (stmt) = NULL_TREE;
+ 	}
+       else
+ 	{
+ #if defined ENABLE_CHECKING
+ 	  /* A return expression is represented by a MODIFY_EXPR node that
+ 	     assigns the return value into a RESULT_DECL.  */
+ 	  if (TREE_CODE (ret_expr) != MODIFY_EXPR
+ 	      && TREE_CODE (ret_expr) != INIT_EXPR)
+ 	    abort ();
+ #endif
+ 
+ 	  /* The grammar calls for a simple VAL here, but the RETURN_STMT
+ 	     already uses a MODIFY_EXPR, and using a full RHS allows us to
+ 	     optimize returning a call to a function of struct type.  */
+ 	  if (is_simple_rhs (TREE_OPERAND (ret_expr, 1)))
+ 	    return;
+ 
+ 	  walk_tree (&TREE_OPERAND (ret_expr, 1), mostly_copy_tree_r,
+ 		     NULL, NULL);
+ 	  simplify_expr (&TREE_OPERAND (ret_expr, 1), pre_p, NULL,
+ 			 is_simple_rhs, fb_rvalue);
+ 	}
+     }
+ }
+ #endif
*** ./c-common.h.~1~	Tue Aug 20 14:20:51 2002
--- ./c-common.h	Wed Aug 21 11:48:48 2002
*************** extern tree strip_array_types           
*** 945,951 ****
  /* RETURN_STMT accessors. These give the expression associated with a
     return statement, and whether it should be ignored when expanding
     (as opposed to inlining).  */
! #define RETURN_EXPR(NODE)       TREE_OPERAND (RETURN_STMT_CHECK (NODE), 0)
  
  /* EXPR_STMT accessor. This gives the expression associated with an
     expression statement.  */
--- 945,951 ----
  /* RETURN_STMT accessors. These give the expression associated with a
     return statement, and whether it should be ignored when expanding
     (as opposed to inlining).  */
! #define RETURN_STMT_EXPR(NODE)  TREE_OPERAND (RETURN_STMT_CHECK (NODE), 0)
  
  /* EXPR_STMT accessor. This gives the expression associated with an
     expression statement.  */
*** ./tree-dfa.c.~1~	Tue Aug 20 14:21:23 2002
--- ./tree-dfa.c	Wed Aug 21 12:46:51 2002
*************** find_refs_in_stmt (t, bb)
*** 179,185 ****
        break;
  
      case RETURN_STMT:
!       find_refs_in_expr (&RETURN_EXPR (t), VARUSE, bb, t, RETURN_EXPR (t));
        break;
  
      case GOTO_STMT:
--- 179,185 ----
        break;
  
      case RETURN_STMT:
!       find_refs_in_expr (&RETURN_STMT_EXPR (t), VARUSE, bb, t, RETURN_STMT_EXPR (t));
        break;
  
      case GOTO_STMT:
*** ./c-pretty-print.c.~1~	Tue Aug 20 14:20:54 2002
--- ./c-pretty-print.c	Thu Aug 22 17:51:18 2002
*************** dump_c_node (buffer, node, spc, brief_du
*** 178,184 ****
        break;
  
      case IDENTIFIER_NODE:
!       output_add_string (buffer, IDENTIFIER_POINTER (node));
        break;
  
      case TREE_LIST:
--- 178,184 ----
        break;
  
      case IDENTIFIER_NODE:
!       output_add_identifier (buffer, node);
        break;
  
      case TREE_LIST:
*************** dump_c_node (buffer, node, spc, brief_du
*** 232,239 ****
  	if (class == 'd')
  	  {
  	    if (DECL_NAME (node))
! 	      output_add_string (buffer, 
! 				 IDENTIFIER_POINTER (DECL_NAME (node)));
  	    else
                output_add_string (buffer, "<unnamed type decl>");
  	  }
--- 232,238 ----
  	if (class == 'd')
  	  {
  	    if (DECL_NAME (node))
! 	      output_add_identifier (buffer, DECL_NAME (node));
  	    else
                output_add_string (buffer, "<unnamed type decl>");
  	  }
*************** dump_c_node (buffer, node, spc, brief_du
*** 647,656 ****
        break;
  
      case COMPOUND_EXPR:
!       dump_c_node (buffer, TREE_OPERAND (node, 0), spc, brief_dump);
!       output_add_character (buffer, ',');
!       output_add_space (buffer);
!       dump_c_node (buffer, TREE_OPERAND (node, 1), spc, brief_dump);
        break;
  
      case MODIFY_EXPR:
--- 646,675 ----
        break;
  
      case COMPOUND_EXPR:
!       if (TREE_TYPE (node) == void_type_node)
! 	{
! 	  for (; TREE_CODE (node) == COMPOUND_EXPR;
! 	       node = TREE_OPERAND (node, 1))
! 	    {
! 	      INDENT (spc);
! 	      dump_c_node (buffer, TREE_OPERAND (node, 0), spc, brief_dump);
! 	      output_add_character (buffer, ';');
! 	      if (!brief_dump)
! 		output_add_newline (buffer);
! 	    }
! 	  INDENT (spc);
! 	  dump_c_node (buffer, node, spc, brief_dump);
! 	  output_add_character (buffer, ';');
! 	  if (!brief_dump)
! 	    output_add_newline (buffer);
! 	}
!       else
! 	{
! 	  dump_c_node (buffer, TREE_OPERAND (node, 0), spc, brief_dump);
! 	  output_add_character (buffer, ',');
! 	  output_add_space (buffer);
! 	  dump_c_node (buffer, TREE_OPERAND (node, 1), spc, brief_dump);
! 	}
        break;
  
      case MODIFY_EXPR:
*************** dump_c_node (buffer, node, spc, brief_du
*** 670,688 ****
        break;
  
      case COND_EXPR:
!       dump_c_node (buffer, TREE_OPERAND (node, 0), spc, brief_dump);
!       output_add_space (buffer);
!       output_add_character (buffer, '?');
!       output_add_space (buffer);
!       dump_c_node (buffer, TREE_OPERAND (node, 1), spc, brief_dump);
!       output_add_space (buffer);
!       output_add_character (buffer, ':');
!       output_add_space (buffer);
!       dump_c_node (buffer, TREE_OPERAND (node, 2), spc, brief_dump);
        break;
  
      case BIND_EXPR:
!       NIY;
  
      case CALL_EXPR:
        print_call_name (buffer, node);
--- 689,744 ----
        break;
  
      case COND_EXPR:
!       if (TREE_TYPE (node) == void_type_node)
! 	{
! 	  INDENT (spc);
! 	  output_add_string (buffer, "if (");
! 	  dump_c_node (buffer, TREE_OPERAND (node, 0), spc, brief_dump);
! 	  output_add_character (buffer, ')');
! 	  if (!brief_dump)
! 	    {
! 	      output_add_newline (buffer);
! 	      dump_c_node (buffer, TREE_OPERAND (node, 1), spc+2, brief_dump);
! 	      if (TREE_OPERAND (node, 2) != void_zero_node)
! 		{
! 		  INDENT (spc);
! 		  output_add_string (buffer, "else");
! 		  output_add_newline (buffer);
! 		  dump_c_node (buffer, TREE_OPERAND (node, 2), spc+2, brief_dump);
! 		}
! 	    }
! 	}
!       else
! 	{
! 	  dump_c_node (buffer, TREE_OPERAND (node, 0), spc, brief_dump);
! 	  output_add_space (buffer);
! 	  output_add_character (buffer, '?');
! 	  output_add_space (buffer);
! 	  dump_c_node (buffer, TREE_OPERAND (node, 1), spc, brief_dump);
! 	  output_add_space (buffer);
! 	  output_add_character (buffer, ':');
! 	  output_add_space (buffer);
! 	  dump_c_node (buffer, TREE_OPERAND (node, 2), spc, brief_dump);
! 	}
        break;
  
      case BIND_EXPR:
!       INDENT (spc);
!       output_add_character (buffer, '{');
!       if (!brief_dump)
! 	output_add_newline (buffer);
!       spc += 2;
! 
!       for (op0 = BIND_EXPR_VARS (node); op0; op0 = TREE_CHAIN (op0))
! 	print_declaration (buffer, op0, spc, brief_dump);
!       
!       dump_c_node (buffer, BIND_EXPR_BODY (node), spc, brief_dump);
!       spc -= 2;
!       INDENT (spc);
!       output_add_character (buffer, '}');
!       if (!brief_dump)
! 	output_add_newline (buffer);
!       break;
  
      case CALL_EXPR:
        print_call_name (buffer, node);
*************** dump_c_node (buffer, node, spc, brief_du
*** 963,982 ****
        output_add_newline (buffer);
        break;
  
-     case GOTO_EXPR:
-       NIY;
- 
-     case EXIT_EXPR:
-       NIY;
- 
-     case LOOP_EXPR:
-       NIY;
- 
      case LABELED_BLOCK_EXPR:
!       NIY;
  
      case EXIT_BLOCK_EXPR:
!       NIY;
  
      case EXPR_WITH_FILE_LOCATION:
        dump_c_node (buffer, TREE_OPERAND (node, 0), spc, brief_dump);
--- 1019,1050 ----
        output_add_newline (buffer);
        break;
  
      case LABELED_BLOCK_EXPR:
!       INDENT (spc);
!       dump_c_node (buffer, LABELED_BLOCK_LABEL (node), spc, brief_dump);
!       output_add_string (buffer, ": {");
!       if (!brief_dump)
! 	output_add_newline (buffer);
!       spc += 2;
!       INDENT (spc);
!       dump_c_node (buffer, LABELED_BLOCK_BODY (node), spc, brief_dump);
!       spc -= 2;
!       INDENT (spc);
!       output_add_character (buffer, '}');
!       if (!brief_dump)
! 	output_add_newline (buffer);
!       break;
  
      case EXIT_BLOCK_EXPR:
!       INDENT (spc);
!       output_add_string (buffer, "<<<exit block ");
!       dump_c_node (buffer,
! 		   LABELED_BLOCK_LABEL (EXIT_BLOCK_LABELED_BLOCK (node)),
! 		   spc, brief_dump);
!       output_add_string (buffer, ">>>");
!       if (!brief_dump)
! 	output_add_newline (buffer);
!       break;
  
      case EXPR_WITH_FILE_LOCATION:
        dump_c_node (buffer, TREE_OPERAND (node, 0), spc, brief_dump);
*************** dump_c_node (buffer, node, spc, brief_du
*** 1080,1085 ****
--- 1148,1168 ----
  	}
        break;
  
+     case LOOP_EXPR:
+       INDENT (spc);
+       output_add_string (buffer, "while (1) {");
+       if (!brief_dump)
+ 	{
+ 	  output_add_newline (buffer);
+ 	  dump_c_node (buffer, LOOP_EXPR_BODY (node), spc+2, brief_dump);
+ 	}
+       INDENT (spc);
+       output_add_character (buffer, '}');
+       if (!brief_dump)
+ 	output_add_newline (buffer);
+       break;
+ 
+       
      case WHILE_STMT:
        INDENT (spc);
        output_add_string (buffer, "while (");
*************** dump_c_node (buffer, node, spc, brief_du
*** 1112,1133 ****
        break;
  
      case RETURN_STMT:
        INDENT (spc);
        output_add_string (buffer, "return");
!       if (RETURN_EXPR (node))
  	{
  	  output_add_space (buffer);
! 	  if (TREE_CODE (RETURN_EXPR (node)) == MODIFY_EXPR)
! 	    dump_c_node (buffer, TREE_OPERAND (RETURN_EXPR (node), 1), spc,
! 			 brief_dump);
  	  else
! 	    dump_c_node (buffer, RETURN_EXPR (node), spc, brief_dump);
  	}
        output_add_character (buffer, ';');
        if (!brief_dump)
  	output_add_newline (buffer);
        break;
  
      case BREAK_STMT:
        INDENT (spc);
        output_add_string (buffer, "break;");
--- 1195,1226 ----
        break;
  
      case RETURN_STMT:
+     case RETURN_EXPR:
        INDENT (spc);
        output_add_string (buffer, "return");
!       op0 = TREE_OPERAND (node, 0);
!       if (op0)
  	{
  	  output_add_space (buffer);
! 	  if (TREE_CODE (op0) == MODIFY_EXPR)
! 	    dump_c_node (buffer, TREE_OPERAND (op0, 1), spc, brief_dump);
  	  else
! 	    dump_c_node (buffer, op0, spc, brief_dump);
  	}
        output_add_character (buffer, ';');
        if (!brief_dump)
  	output_add_newline (buffer);
        break;
  
+     case EXIT_EXPR:
+       INDENT (spc);
+       output_add_string (buffer, "if (");
+       dump_c_node (buffer, TREE_OPERAND (node, 0), spc, brief_dump);
+       output_add_string (buffer, ") break;");
+       if (!brief_dump)
+ 	output_add_newline (buffer);
+       break;
+ 
      case BREAK_STMT:
        INDENT (spc);
        output_add_string (buffer, "break;");
*************** dump_c_node (buffer, node, spc, brief_du
*** 1154,1163 ****
  	}
        break;
  
      case GOTO_STMT:
        INDENT (spc);
        output_add_string (buffer, "goto ");
!       dump_c_node (buffer, GOTO_DESTINATION (node), spc, brief_dump);
        output_add_character (buffer, ';');
        if (!brief_dump)
  	output_add_newline (buffer);
--- 1247,1257 ----
  	}
        break;
  
+     case GOTO_EXPR:
      case GOTO_STMT:
        INDENT (spc);
        output_add_string (buffer, "goto ");
!       dump_c_node (buffer, TREE_OPERAND (node, 0), spc, brief_dump);
        output_add_character (buffer, ';');
        if (!brief_dump)
  	output_add_newline (buffer);
*** ./tree-inline.c.~1~	Tue Aug 20 14:21:23 2002
--- ./tree-inline.c	Fri Aug 23 09:58:25 2002
*************** copy_body_r (tp, walk_subtrees, data)
*** 442,451 ****
  	 assignment into the equivalent of the original
  	 RESULT_DECL.  */
  #ifndef INLINER_FOR_JAVA
!       if (RETURN_EXPR (return_stmt))
  	{
  	  *tp = build_stmt (EXPR_STMT,
! 			    RETURN_EXPR (return_stmt));
  	  STMT_IS_FULL_EXPR_P (*tp) = 1;
  	  /* And then jump to the end of the function.  */
  	  TREE_CHAIN (*tp) = goto_stmt;
--- 442,451 ----
  	 assignment into the equivalent of the original
  	 RESULT_DECL.  */
  #ifndef INLINER_FOR_JAVA
!       if (RETURN_STMT_EXPR (return_stmt))
  	{
  	  *tp = build_stmt (EXPR_STMT,
! 			    RETURN_STMT_EXPR (return_stmt));
  	  STMT_IS_FULL_EXPR_P (*tp) = 1;
  	  /* And then jump to the end of the function.  */
  	  TREE_CHAIN (*tp) = goto_stmt;
*************** copy_body (id)
*** 569,574 ****
--- 569,577 ----
    body = DECL_SAVED_TREE (VARRAY_TOP_TREE (id->fns));
    walk_tree (&body, copy_body_r, id, NULL);
  
+   if (!statement_code_p (TREE_CODE (body)))
+     body = build_stmt (EXPR_STMT, body);
+ 
    return body;
  }
  
*************** expand_call_inline (tp, walk_subtrees, d
*** 972,977 ****
--- 975,981 ----
  #else /* INLINER_FOR_JAVA */
    tree retvar;
  #endif /* INLINER_FOR_JAVA */
+   tree decl;
    tree fn;
    tree arg_inits;
    tree *inlined_body;
*************** expand_call_inline (tp, walk_subtrees, d
*** 1154,1174 ****
      BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope_stmt)) = DECL_ORIGIN (fn);
  
    /* Declare the return variable for the function.  */
!   COMPOUND_BODY (stmt)
!     = chainon (COMPOUND_BODY (stmt),
! 	       declare_return_variable (id, &use_stmt));
! #else /* INLINER_FOR_JAVA */
!   {
!     /* Declare the return variable for the function.  */
!     tree decl = declare_return_variable (id, &retvar);
!     if (retvar)
!       {
! 	tree *next = &BLOCK_VARS (expr);
! 	while (*next)
! 	  next = &TREE_CHAIN (*next);	
! 	*next = decl;
!       }
!   }
  #endif /* INLINER_FOR_JAVA */
  
    /* After we've initialized the parameters, we insert the body of the
--- 1158,1182 ----
      BLOCK_ABSTRACT_ORIGIN (SCOPE_STMT_BLOCK (scope_stmt)) = DECL_ORIGIN (fn);
  
    /* Declare the return variable for the function.  */
!   decl = declare_return_variable (id, &use_stmt);
!   COMPOUND_BODY (stmt) = chainon (COMPOUND_BODY (stmt), decl);
!   if (TREE_CODE (decl) == DECL_STMT)
!     BLOCK_VARS (SCOPE_STMT_BLOCK (scope_stmt))
!       = chainon (BLOCK_VARS (SCOPE_STMT_BLOCK (scope_stmt)),
! 		 DECL_STMT_DECL (decl));
!   else
!     abort ();
! 	
! #else /* INLINER_FOR_JAVA */
!   /* Declare the return variable for the function.  */
!   decl = declare_return_variable (id, &retvar);
!   if (retvar)
!     {
!       tree *next = &BLOCK_VARS (expr);
!       while (*next)
! 	next = &TREE_CHAIN (*next);	
!       *next = decl;
!     }
  #endif /* INLINER_FOR_JAVA */
  
    /* After we've initialized the parameters, we insert the body of the
*** ./c-semantics.c.~1~	Tue Aug 20 14:20:54 2002
--- ./c-semantics.c	Wed Aug 21 13:19:27 2002
*************** build_stmt VPARAMS ((enum tree_code code
*** 196,201 ****
--- 196,204 ----
    length = TREE_CODE_LENGTH (code);
    STMT_LINENO (t) = lineno;
  
+   if (code != EXPR_STMT)
+     TREE_SIDE_EFFECTS (t) = 1;
+ 
    for (i = 0; i < length; i++)
      TREE_OPERAND (t, i) = va_arg (p, tree);
  
*************** genrtl_return_stmt (stmt)
*** 487,493 ****
  {
    tree expr;
  
!   expr = RETURN_EXPR (stmt);
  
    emit_line_note (input_filename, lineno);
    if (!expr)
--- 490,496 ----
  {
    tree expr;
  
!   expr = RETURN_STMT_EXPR (stmt);
  
    emit_line_note (input_filename, lineno);
    if (!expr)
*** ./diagnostic.c.~1~	Tue Aug 20 14:21:03 2002
--- ./diagnostic.c	Thu Aug 22 14:06:15 2002
*************** output_add_string (buffer, str)
*** 463,468 ****
--- 463,476 ----
    maybe_wrap_text (buffer, str, str + (str ? strlen (str) : 0));
  }
  
+ void
+ output_add_identifier (buffer, id)
+      output_buffer *buffer;
+      tree id;
+ {
+   output_add_string (buffer, IDENTIFIER_POINTER (id));
+ }
+ 
  /* Flush the content of BUFFER onto the attached stream,
     and reinitialize.  */
  

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