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


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

[patch] Decompose gimplify_expr


Hello,

this patch replaces the gimplify_expr function that may
return anything (gimple operand, gimple rhs, list of gimple statements,
...) depending on predicate sent to it, by separate functions for
each possible return type (i.e. new functions like gimplify_to_operand,
gimplify_to_rhs, etc. are introduced).  The current behavior of
gimplify_expr is the main reason that prevents any principial
improvements to gimplification (see my gcc summit paper for more
details).

There should not be any intentional changes in functionality (the
produced code is not completely identical -- a few things get done
a bit differently by the specific gimplification functions than they
were done by a generic fallback machinery -- but there should not be
great differences).

The core of gimplify_expr is preserved as gimplify_main -- this function
gimplifies the expression to gimple rhs, plus we may ask it to either
ignore the return value and gimplify only side effects, or to work hard
on preserving lvalueness of the expression.  The other gimplification
functions are usually just simple wrappers around gimplify_main that
post-process its results.

I do not plan to post any further changes to gimplification after this
patch for now; the main reason for this patch is to minimize the
divergence between mainline and the gimplification improvements branch
I am about to create (the other changes are more localized and easier
to keep up-to-date with mainline changes, while this one is moves the
code around quite a bit and is quite large, thus making basically
any other change to conflict with it).

Bootstrapped & regtested on i686, x86_64 and ia64.

Zdenek

	* gimplify.c (MUST_PRESERVE_LVALUE): New flag.
	(gimplify_main, gimplify_to_void, gimplify_rhs_to_operand,
	gimplify_to_operand, gimplify_to_call_addr, gimplify_to_rhs,
	gimplify_to_assignment_rhs, gimplify_to_addressable,
	gimplify_to_lhs, gimplify_to_min_lval, gimplify_to_condexpr,
	gimplify_to_asm_val): New functions, split from ...
	(gimplify_expr): ..., removed.
	(lookup_tmp_var): Always mark the new variable as
	DECL_GIMPLE_FORMAL_TEMP_P.
	(internal_get_tmp_var, gimplify_and_add, gimplify_one_sizepos,
	force_gimple_operand): Use specific gimplify_to_...
	functions instead of gimplify_expr.
	(gimplify_bind_expr, gimplify_return_expr, gimplify_decl_expr,
	gimplify_loop_expr, gimplify_switch_expr, gimplify_case_label_expr,
	gimplify_exit_expr, gimplify_conversion, gimplify_compound_lval,
	gimplify_self_mod_expr, gimplify_arg, gimplify_call_expr,
	gimplify_cond_expr, gimplify_init_ctor_preeval,
	gimplify_init_ctor_eval_range, gimplify_init_ctor_eval,
	gimplify_init_constructor, gimplify_modify_expr_rhs,
	gimplify_modify_expr_complex_part, gimplify_modify_expr,
	gimplify_variable_sized_compare, gimplify_boolean_expr,
	gimplify_compound_expr, gimplify_statement_list,
	gimplify_save_expr, gimplify_addr_expr, gimplify_save_expr,
	gimplify_asm_expr, gimplify_cleanup_point_expr, gimple_push_cleanup,
	gimplify_target_expr, gimplify_stmt): Ditto.  Do not return statement
	lists in *EXPR_P.
	(add_statement, forget_memory_reference, gimplify_unary_expr,
	gimplify_constructor, gimplify_indirect_ref,
	gimplify_binary_expr, gimplify_const_decl, gimplify_goto_expr,
	gimplify_label_expr, gimplify_try_finally_expr,
	gimplify_try_catch_expr, gimplify_catch_expr,
	gimplify_eh_filter_expr, gimplify_obj_type_ref,
	gimplify_with_size_expr): New functions.
	* tree-gimple.c (rhs_predicate_for): Replaced with ...
	(is_gimple_rhs_for): ... new function.
	* tree-gimple.h (gimple_predicate, rhs_predicate_for): Removed.
	(is_gimple_rhs_for): Declare.
	(enum fallback_t, gimplify_expr): Removed.
	(gimplify_to_void, gimplify_rhs_to_operand, gimplify_to_operand,
	gimplify_to_call_addr, gimplify_to_rhs,
	gimplify_to_assignment_rhs, gimplify_to_addressable,
	gimplify_to_lhs, gimplify_to_min_lval, gimplify_to_condexpr,
	gimplify_to_asm_val): Declare.
	* builtins.c (std_gimplify_va_arg_expr, gimplify_va_arg_expr):
	Use specific gimplify_to_... functions instead of gimplify_expr.
	* config/alpha/alpha.c (alpha_gimplify_va_arg_1): Ditto.
	* config/i386/i386.c (ix86_gimplify_va_arg): Ditto.
	* config/rs6000/rs6000.c (rs6000_gimplify_va_arg): Ditto.
	* config/s390/s390.c (s390_gimplify_va_arg): Ditto.
	* config/sparc/sparc.c (sparc_gimplify_va_arg): Ditto.
	* config/stormy16/stormy16.c (xstormy16_expand_builtin_va_arg): Ditto.
	* config/xtensa/xtensa.c (xtensa_gimplify_va_arg_expr): Ditto.
	* cp/cp-gimplify.c (gimplify_for_stmt, cp_gimplify_init_expr,
	cp_gimplify_expr): Ditto.  Never return statements in *EXPR_P.
	* java/java-gimplify.c (java_gimplify_expr): Ditto.
	* objc/objc-act.c (objc_gimplify_expr): Ditto.
	* doc/passes.texi: Replace references to gimplify_expr with
	gimplify_main.
	* doc/tm.texi: Ditto.

Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.468
diff -c -3 -p -r1.468 builtins.c
*** builtins.c	12 Jul 2005 09:19:59 -0000	1.468
--- builtins.c	22 Jul 2005 03:42:28 -0000
*************** std_gimplify_va_arg_expr (tree valist, t
*** 4174,4180 ****
    rounded_size = round_up (type_size, align);
  
    /* Reduce rounded_size so it's sharable with the postqueue.  */
!   gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
  
    /* Get AP.  */
    addr = valist_tmp;
--- 4174,4180 ----
    rounded_size = round_up (type_size, align);
  
    /* Reduce rounded_size so it's sharable with the postqueue.  */
!   gimplify_to_operand (rounded_size, pre_p, post_p, &rounded_size, false);
  
    /* Get AP.  */
    addr = valist_tmp;
*************** gimplify_va_arg_expr (tree *expr_p, tree
*** 4309,4318 ****
  	      tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
  	      valist = build_fold_addr_expr_with_type (valist, p1);
  	    }
! 	  gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
  	}
        else
! 	gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
  
        if (!targetm.gimplify_va_arg_expr)
  	/* FIXME:Once most targets are converted we should merely
--- 4309,4318 ----
  	      tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
  	      valist = build_fold_addr_expr_with_type (valist, p1);
  	    }
! 	  gimplify_to_operand (valist, pre_p, post_p, &valist, false);
  	}
        else
! 	gimplify_to_min_lval (valist, pre_p, post_p, &valist);
  
        if (!targetm.gimplify_va_arg_expr)
  	/* FIXME:Once most targets are converted we should merely
Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.142
diff -c -3 -p -r2.142 gimplify.c
*** gimplify.c	20 Jul 2005 01:18:18 -0000	2.142
--- gimplify.c	22 Jul 2005 03:42:33 -0000
*************** typedef struct gimple_temp_hash_elt
*** 73,83 ****
  } elt_t;
  
  /* Forward declarations.  */
! static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
  #ifdef ENABLE_CHECKING
  static bool cpt_same_type (tree a, tree b);
  #endif
  
  
  /* Return a hash value for a formal temporary table entry.  */
  
--- 73,95 ----
  } elt_t;
  
  /* Forward declarations.  */
! static enum gimplify_status gimplify_compound_expr (tree *, tree *, tree *,
! 						    bool);
  #ifdef ENABLE_CHECKING
  static bool cpt_same_type (tree a, tree b);
  #endif
  
+ /* Flags for gimplify_main.  */
+ 
+ enum
+ {
+   MUST_PRESERVE_LVALUE = 1	/* If this flag is set, gimplify_main is
+ 				   guaranteed to preserve the fact that
+ 				   the expression is a lhs.  */
+ };
+ 
+ static enum gimplify_status gimplify_main (tree, tree *, tree *, tree *,
+ 					   unsigned);
  
  /* Return a hash value for a formal temporary table entry.  */
  
*************** append_to_statement_list (tree t, tree *
*** 246,252 ****
      append_to_statement_list_1 (t, list_p);
  }
  
! /* Similar, but the statement is always added, regardless of side effects.  */
  
  void
  append_to_statement_list_force (tree t, tree *list_p)
--- 258,265 ----
      append_to_statement_list_1 (t, list_p);
  }
  
! /* Similar to append_to_statement_list, but the statement is always added,
!    regardless of side effects.  */
  
  void
  append_to_statement_list_force (tree t, tree *list_p)
*************** append_to_statement_list_force (tree t, 
*** 255,269 ****
      append_to_statement_list_1 (t, list_p);
  }
  
- /* Both gimplify the statement T and append it to LIST_P.  */
- 
- void
- gimplify_and_add (tree t, tree *list_p)
- {
-   gimplify_stmt (&t);
-   append_to_statement_list (t, list_p);
- }
- 
  /* Strip off a legitimate source ending from the input string NAME of
     length LEN.  Rather than having to know the names used by all of
     our front ends, we strip off an ending of a period followed by
--- 268,273 ----
*************** lookup_tmp_var (tree val, bool is_formal
*** 443,456 ****
  	}
      }
  
!   if (is_formal)
!     DECL_GIMPLE_FORMAL_TEMP_P (ret) = 1;
! 
    return ret;
  }
  
  /* Returns a formal temporary variable initialized with VAL.  PRE_P is as
!    in gimplify_expr.  Only use this function if:
  
     1) The value of the unfactored expression represented by VAL will not
        change between the initialization and use of the temporary, and
--- 447,458 ----
  	}
      }
  
!   DECL_GIMPLE_FORMAL_TEMP_P (ret) = 1;
    return ret;
  }
  
  /* Returns a formal temporary variable initialized with VAL.  PRE_P is as
!    in gimplify_main.  Only use this function if:
  
     1) The value of the unfactored expression represented by VAL will not
        change between the initialization and use of the temporary, and
*************** internal_get_tmp_var (tree val, tree *pr
*** 466,472 ****
  {
    tree t, mod;
  
!   gimplify_expr (&val, pre_p, post_p, is_gimple_formal_tmp_rhs, fb_rvalue);
  
    t = lookup_tmp_var (val, is_formal);
  
--- 468,474 ----
  {
    tree t, mod;
  
!   gimplify_to_rhs (val, pre_p, post_p, &val);
  
    t = lookup_tmp_var (val, is_formal);
  
*************** internal_get_tmp_var (tree val, tree *pr
*** 481,487 ****
      SET_EXPR_LOCATION (mod, input_location);
  
    /* gimplify_modify_expr might want to reduce this further.  */
!   gimplify_and_add (mod, pre_p);
  
    /* If we're gimplifying into ssa, gimplify_modify_expr will have
       given our temporary an ssa name.  Find and return it.  */
--- 483,489 ----
      SET_EXPR_LOCATION (mod, input_location);
  
    /* gimplify_modify_expr might want to reduce this further.  */
!   gimplify_to_void (mod, pre_p);
  
    /* If we're gimplifying into ssa, gimplify_modify_expr will have
       given our temporary an ssa name.  Find and return it.  */
*************** get_formal_tmp_var (tree val, tree *pre_
*** 498,504 ****
  }
  
  /* Returns a temporary variable initialized with VAL.  PRE_P and POST_P
!    are as in gimplify_expr.  */
  
  tree
  get_initialized_tmp_var (tree val, tree *pre_p, tree *post_p)
--- 500,506 ----
  }
  
  /* Returns a temporary variable initialized with VAL.  PRE_P and POST_P
!    are as in gimplify_main.  */
  
  tree
  get_initialized_tmp_var (tree val, tree *pre_p, tree *post_p)
*************** annotate_all_with_locus (tree *stmt_p, l
*** 594,599 ****
--- 596,619 ----
      }
  }
  
+ /* Similar to append_to_statement_list, but also annotate the
+    new statements with locus.  Statement T is added to the
+    list LIST_P, if it has any side effects.  */
+ 
+ static void
+ add_statement (tree t, tree *list_p)
+ {
+   if (!t || !TREE_SIDE_EFFECTS (t))
+     return;
+ 
+   if (TREE_CODE (t) == STATEMENT_LIST)
+     annotate_all_with_locus (&t, input_location);
+   else
+     annotate_one_with_locus (t, input_location);
+ 
+   append_to_statement_list_1 (t, list_p);
+ }
+ 
  /* Similar to copy_tree_r() but do not copy SAVE_EXPR or TARGET_EXPR nodes.
     These nodes model computations that should only be done once.  If we
     were to unshare something like SAVE_EXPR(i++), the gimplification
*************** build_stack_save_restore (tree *save, tr
*** 849,855 ****
  /* Gimplify a BIND_EXPR.  Just voidify and recurse.  */
  
  static enum gimplify_status
! gimplify_bind_expr (tree *expr_p, tree temp, tree *pre_p)
  {
    tree bind_expr = *expr_p;
    bool old_save_stack = gimplify_ctxp->save_stack;
--- 869,875 ----
  /* Gimplify a BIND_EXPR.  Just voidify and recurse.  */
  
  static enum gimplify_status
! gimplify_bind_expr (tree *expr_p, tree temp, tree *pre_p, bool want_value)
  {
    tree bind_expr = *expr_p;
    bool old_save_stack = gimplify_ctxp->save_stack;
*************** gimplify_bind_expr (tree *expr_p, tree t
*** 889,915 ****
  
        t = build (TRY_FINALLY_EXPR, void_type_node,
  		 BIND_EXPR_BODY (bind_expr), NULL_TREE);
!       append_to_statement_list (stack_restore, &TREE_OPERAND (t, 1));
  
        BIND_EXPR_BODY (bind_expr) = NULL_TREE;
!       append_to_statement_list (stack_save, &BIND_EXPR_BODY (bind_expr));
!       append_to_statement_list (t, &BIND_EXPR_BODY (bind_expr));
      }
  
    gimplify_ctxp->save_stack = old_save_stack;
    gimple_pop_bind_expr ();
  
!   if (temp)
      {
!       *expr_p = temp;
!       append_to_statement_list (bind_expr, pre_p);
!       return GS_OK;
      }
!   else
!     return GS_ALL_DONE;
  }
  
! /* Gimplify a RETURN_EXPR.  If the expression to be returned is not a
     GIMPLE value, it is assigned to a new temporary and the statement is
     re-written to return the temporary.
  
--- 909,938 ----
  
        t = build (TRY_FINALLY_EXPR, void_type_node,
  		 BIND_EXPR_BODY (bind_expr), NULL_TREE);
!       add_statement (stack_restore, &TREE_OPERAND (t, 1));
  
        BIND_EXPR_BODY (bind_expr) = NULL_TREE;
!       add_statement (stack_save, &BIND_EXPR_BODY (bind_expr));
!       add_statement (t, &BIND_EXPR_BODY (bind_expr));
      }
  
    gimplify_ctxp->save_stack = old_save_stack;
    gimple_pop_bind_expr ();
  
!   add_statement (bind_expr, pre_p);
! 
!   if (!want_value)
      {
!       *expr_p = NULL_TREE;
!       return GS_ALL_DONE;
      }
! 
!   gcc_assert (temp);
!   *expr_p = temp;
!   return GS_OK;
  }
  
! /* Gimplify a RETURN_EXPR *STMT_P.  If the expression to be returned is not a
     GIMPLE value, it is assigned to a new temporary and the statement is
     re-written to return the temporary.
  
*************** gimplify_bind_expr (tree *expr_p, tree t
*** 917,930 ****
     STMT should be stored.  */
  
  static enum gimplify_status
! gimplify_return_expr (tree stmt, tree *pre_p)
  {
    tree ret_expr = TREE_OPERAND (stmt, 0);
    tree result_decl, result;
  
    if (!ret_expr || TREE_CODE (ret_expr) == RESULT_DECL
        || ret_expr == error_mark_node)
!     return GS_ALL_DONE;
  
    if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
      result_decl = NULL_TREE;
--- 940,958 ----
     STMT should be stored.  */
  
  static enum gimplify_status
! gimplify_return_expr (tree *stmt_p, tree *pre_p)
  {
+   tree stmt = *stmt_p;
    tree ret_expr = TREE_OPERAND (stmt, 0);
    tree result_decl, result;
  
+   *stmt_p = NULL_TREE;
    if (!ret_expr || TREE_CODE (ret_expr) == RESULT_DECL
        || ret_expr == error_mark_node)
!     {
!       add_statement (stmt, pre_p);
!       return GS_ALL_DONE;
!     }
  
    if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
      result_decl = NULL_TREE;
*************** gimplify_return_expr (tree stmt, tree *p
*** 971,985 ****
    if (result != result_decl)
      TREE_OPERAND (ret_expr, 0) = result;
  
!   gimplify_and_add (TREE_OPERAND (stmt, 0), pre_p);
  
    /* If we didn't use a temporary, then the result is just the result_decl.
       Otherwise we need a simple copy.  This should already be gimple.  */
    if (result == result_decl)
      ret_expr = result;
    else
!     ret_expr = build (MODIFY_EXPR, TREE_TYPE (result), result_decl, result);
    TREE_OPERAND (stmt, 0) = ret_expr;
  
    return GS_ALL_DONE;
  }
--- 999,1014 ----
    if (result != result_decl)
      TREE_OPERAND (ret_expr, 0) = result;
  
!   gimplify_to_void (TREE_OPERAND (stmt, 0), pre_p);
  
    /* If we didn't use a temporary, then the result is just the result_decl.
       Otherwise we need a simple copy.  This should already be gimple.  */
    if (result == result_decl)
      ret_expr = result;
    else
!     ret_expr = build2 (MODIFY_EXPR, TREE_TYPE (result), result_decl, result);
    TREE_OPERAND (stmt, 0) = ret_expr;
+   add_statement (stmt, pre_p);
  
    return GS_ALL_DONE;
  }
*************** gimplify_return_expr (tree stmt, tree *p
*** 988,994 ****
     and initialization explicit.  */
  
  static enum gimplify_status
! gimplify_decl_expr (tree *stmt_p)
  {
    tree stmt = *stmt_p;
    tree decl = DECL_EXPR_DECL (stmt);
--- 1017,1023 ----
     and initialization explicit.  */
  
  static enum gimplify_status
! gimplify_decl_expr (tree *stmt_p, tree *pre_p, tree *post_p ATTRIBUTE_UNUSED)
  {
    tree stmt = *stmt_p;
    tree decl = DECL_EXPR_DECL (stmt);
*************** gimplify_decl_expr (tree *stmt_p)
*** 1001,1007 ****
    if ((TREE_CODE (decl) == TYPE_DECL
         || TREE_CODE (decl) == VAR_DECL)
        && !TYPE_SIZES_GIMPLIFIED (TREE_TYPE (decl)))
!     gimplify_type_sizes (TREE_TYPE (decl), stmt_p);
  
    if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
      {
--- 1030,1036 ----
    if ((TREE_CODE (decl) == TYPE_DECL
         || TREE_CODE (decl) == VAR_DECL)
        && !TYPE_SIZES_GIMPLIFIED (TREE_TYPE (decl)))
!     gimplify_type_sizes (TREE_TYPE (decl), pre_p);
  
    if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
      {
*************** gimplify_decl_expr (tree *stmt_p)
*** 1014,1021 ****
  	     of the emitted code: see mx_register_decls().  */
  	  tree t, args, addr, ptr_type;
  
! 	  gimplify_one_sizepos (&DECL_SIZE (decl), stmt_p);
! 	  gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), stmt_p);
  
  	  /* All occurrences of this decl in final gimplified code will be
  	     replaced by indirection.  Setting DECL_VALUE_EXPR does two
--- 1043,1050 ----
  	     of the emitted code: see mx_register_decls().  */
  	  tree t, args, addr, ptr_type;
  
! 	  gimplify_one_sizepos (&DECL_SIZE (decl), pre_p);
! 	  gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), pre_p);
  
  	  /* All occurrences of this decl in final gimplified code will be
  	     replaced by indirection.  Setting DECL_VALUE_EXPR does two
*************** gimplify_decl_expr (tree *stmt_p)
*** 1035,1041 ****
  	  t = fold_convert (ptr_type, t);
  	  t = build2 (MODIFY_EXPR, void_type_node, addr, t);
  
! 	  gimplify_and_add (t, stmt_p);
  
  	  /* Indicate that we need to restore the stack level when the
  	     enclosing BIND_EXPR is exited.  */
--- 1064,1070 ----
  	  t = fold_convert (ptr_type, t);
  	  t = build2 (MODIFY_EXPR, void_type_node, addr, t);
  
! 	  gimplify_to_void (t, pre_p);
  
  	  /* Indicate that we need to restore the stack level when the
  	     enclosing BIND_EXPR is exited.  */
*************** gimplify_decl_expr (tree *stmt_p)
*** 1048,1054 ****
  	    {
  	      DECL_INITIAL (decl) = NULL_TREE;
  	      init = build (MODIFY_EXPR, void_type_node, decl, init);
! 	      gimplify_and_add (init, stmt_p);
  	    }
  	  else
  	    /* We must still examine initializers for static variables
--- 1077,1083 ----
  	    {
  	      DECL_INITIAL (decl) = NULL_TREE;
  	      init = build (MODIFY_EXPR, void_type_node, decl, init);
! 	      gimplify_to_void (init, pre_p);
  	    }
  	  else
  	    /* We must still examine initializers for static variables
*************** gimplify_loop_expr (tree *expr_p, tree *
*** 1077,1097 ****
    tree start_label = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
    tree jump_stmt = build_and_jump (&LABEL_EXPR_LABEL (start_label));
  
!   append_to_statement_list (start_label, pre_p);
  
    gimplify_ctxp->exit_label = NULL_TREE;
  
!   gimplify_and_add (LOOP_EXPR_BODY (*expr_p), pre_p);
  
    if (gimplify_ctxp->exit_label)
!     {
!       append_to_statement_list (jump_stmt, pre_p);
!       *expr_p = build1 (LABEL_EXPR, void_type_node, gimplify_ctxp->exit_label);
!     }
!   else
!     *expr_p = jump_stmt;
  
    gimplify_ctxp->exit_label = saved_label;
  
    return GS_ALL_DONE;
  }
--- 1106,1125 ----
    tree start_label = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
    tree jump_stmt = build_and_jump (&LABEL_EXPR_LABEL (start_label));
  
!   add_statement (start_label, pre_p);
  
    gimplify_ctxp->exit_label = NULL_TREE;
  
!   gimplify_to_void (LOOP_EXPR_BODY (*expr_p), pre_p);
!   add_statement (jump_stmt, pre_p);
  
    if (gimplify_ctxp->exit_label)
!     add_statement (build1 (LABEL_EXPR, void_type_node,
! 			   gimplify_ctxp->exit_label),
! 		   pre_p);
  
    gimplify_ctxp->exit_label = saved_label;
+   *expr_p = NULL_TREE;
  
    return GS_ALL_DONE;
  }
*************** gimplify_switch_expr (tree *expr_p, tree
*** 1149,1162 ****
    tree switch_expr = *expr_p;
    enum gimplify_status ret;
  
!   ret = gimplify_expr (&SWITCH_COND (switch_expr), pre_p, NULL,
! 		       is_gimple_val, fb_rvalue);
  
    if (SWITCH_BODY (switch_expr))
      {
        VEC(tree,heap) *labels, *saved_labels;
!       tree label_vec, default_case = NULL_TREE;
        size_t i, len;
  
        /* If someone can be bothered to fill in the labels, they can
  	 be bothered to null out the body too.  */
--- 1177,1191 ----
    tree switch_expr = *expr_p;
    enum gimplify_status ret;
  
!   ret = gimplify_to_operand (SWITCH_COND (switch_expr), pre_p, NULL,
! 			     &SWITCH_COND (switch_expr), false);
  
    if (SWITCH_BODY (switch_expr))
      {
        VEC(tree,heap) *labels, *saved_labels;
!       tree label_vec, default_case = NULL_TREE, default_lab;
        size_t i, len;
+       tree body = NULL_TREE;
  
        /* If someone can be bothered to fill in the labels, they can
  	 be bothered to null out the body too.  */
*************** gimplify_switch_expr (tree *expr_p, tree
*** 1165,1171 ****
        saved_labels = gimplify_ctxp->case_labels;
        gimplify_ctxp->case_labels = VEC_alloc (tree, heap, 8);
  
!       gimplify_to_stmt_list (&SWITCH_BODY (switch_expr));
  
        labels = gimplify_ctxp->case_labels;
        gimplify_ctxp->case_labels = saved_labels;
--- 1194,1200 ----
        saved_labels = gimplify_ctxp->case_labels;
        gimplify_ctxp->case_labels = VEC_alloc (tree, heap, 8);
  
!       gimplify_to_void (SWITCH_BODY (switch_expr), &body);
  
        labels = gimplify_ctxp->case_labels;
        gimplify_ctxp->case_labels = saved_labels;
*************** gimplify_switch_expr (tree *expr_p, tree
*** 1187,1206 ****
  
        label_vec = make_tree_vec (len + 1);
        SWITCH_LABELS (*expr_p) = label_vec;
!       append_to_statement_list (switch_expr, pre_p);
  
        if (! default_case)
  	{
  	  /* If the switch has no default label, add one, so that we jump
  	     around the switch body.  */
! 	  default_case = build (CASE_LABEL_EXPR, void_type_node, NULL_TREE,
! 				NULL_TREE, create_artificial_label ());
! 	  append_to_statement_list (SWITCH_BODY (switch_expr), pre_p);
! 	  *expr_p = build (LABEL_EXPR, void_type_node,
! 			   CASE_LABEL (default_case));
  	}
-       else
- 	*expr_p = SWITCH_BODY (switch_expr);
  
        for (i = 0; i < len; ++i)
  	TREE_VEC_ELT (label_vec, i) = VEC_index (tree, labels, i);
--- 1216,1234 ----
  
        label_vec = make_tree_vec (len + 1);
        SWITCH_LABELS (*expr_p) = label_vec;
!       add_statement (switch_expr, pre_p);
!       add_statement (body, pre_p);
  
        if (! default_case)
  	{
  	  /* If the switch has no default label, add one, so that we jump
  	     around the switch body.  */
! 	  default_case = build3 (CASE_LABEL_EXPR, void_type_node, NULL_TREE,
! 				 NULL_TREE, create_artificial_label ());
! 	  default_lab = build1 (LABEL_EXPR, void_type_node,
! 				CASE_LABEL (default_case));
! 	  add_statement (default_lab, pre_p);
  	}
  
        for (i = 0; i < len; ++i)
  	TREE_VEC_ELT (label_vec, i) = VEC_index (tree, labels, i);
*************** gimplify_switch_expr (tree *expr_p, tree
*** 1213,1231 ****
        SWITCH_BODY (switch_expr) = NULL;
      }
    else
!     gcc_assert (SWITCH_LABELS (switch_expr));
  
    return ret;
  }
  
  static enum gimplify_status
! gimplify_case_label_expr (tree *expr_p)
  {
    tree expr = *expr_p;
  
    gcc_assert (gimplify_ctxp->case_labels);
    VEC_safe_push (tree, heap, gimplify_ctxp->case_labels, expr);
!   *expr_p = build (LABEL_EXPR, void_type_node, CASE_LABEL (expr));
    return GS_ALL_DONE;
  }
  
--- 1241,1266 ----
        SWITCH_BODY (switch_expr) = NULL;
      }
    else
!     {
!       gcc_assert (SWITCH_LABELS (switch_expr));
!       add_statement (switch_expr, pre_p);
!     }
  
+   *expr_p = NULL;
    return ret;
  }
  
  static enum gimplify_status
! gimplify_case_label_expr (tree *expr_p, tree *pre_p)
  {
    tree expr = *expr_p;
  
    gcc_assert (gimplify_ctxp->case_labels);
    VEC_safe_push (tree, heap, gimplify_ctxp->case_labels, expr);
!   expr = build1 (LABEL_EXPR, void_type_node, CASE_LABEL (expr));
!   add_statement (expr, pre_p);
! 
!   *expr_p = NULL_TREE;
    return GS_ALL_DONE;
  }
  
*************** build_and_jump (tree *label_p)
*** 1253,1259 ****
     gimplify_loop_expr through gimplify_ctxp->exit_label.  */
  
  static enum gimplify_status
! gimplify_exit_expr (tree *expr_p)
  {
    tree cond = TREE_OPERAND (*expr_p, 0);
    tree expr;
--- 1288,1294 ----
     gimplify_loop_expr through gimplify_ctxp->exit_label.  */
  
  static enum gimplify_status
! gimplify_exit_expr (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED)
  {
    tree cond = TREE_OPERAND (*expr_p, 0);
    tree expr;
*************** canonicalize_addr_expr (tree *expr_p)
*** 1371,1411 ****
    *expr_p = build1 (ADDR_EXPR, ctype, *expr_p);
  }
  
! /* *EXPR_P is a NOP_EXPR or CONVERT_EXPR.  Remove it and/or other conversions
!    underneath as appropriate.  */
  
! static enum gimplify_status
! gimplify_conversion (tree *expr_p)
  {
!   gcc_assert (TREE_CODE (*expr_p) == NOP_EXPR
! 	      || TREE_CODE (*expr_p) == CONVERT_EXPR);
!   
!   /* Then strip away all but the outermost conversion.  */
!   STRIP_SIGN_NOPS (TREE_OPERAND (*expr_p, 0));
! 
!   /* And remove the outermost conversion if it's useless.  */
!   if (tree_ssa_useless_type_conversion (*expr_p))
!     *expr_p = TREE_OPERAND (*expr_p, 0);
! 
!   /* If we still have a conversion at the toplevel,
!      then canonicalize some constructs.  */
!   if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
!     {
!       tree sub = TREE_OPERAND (*expr_p, 0);
! 
!       /* If a NOP conversion is changing the type of a COMPONENT_REF
! 	 expression, then canonicalize its type now in order to expose more
! 	 redundant conversions.  */
!       if (TREE_CODE (sub) == COMPONENT_REF)
! 	canonicalize_component_ref (&TREE_OPERAND (*expr_p, 0));
! 
!       /* If a NOP conversion is changing a pointer to array of foo
! 	 to a pointer to foo, embed that change in the ADDR_EXPR.  */
!       else if (TREE_CODE (sub) == ADDR_EXPR)
! 	canonicalize_addr_expr (expr_p);
      }
- 
-   return GS_OK;
  }
  
  /* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or IMAGPART_EXPR
--- 1406,1427 ----
    *expr_p = build1 (ADDR_EXPR, ctype, *expr_p);
  }
  
! /* The value of memory reference REF is not used.  Still, we sometimes
!    must perform the load anyway; if this is the case, add the appropriate
!    statement to PRE_P.  */
  
! static void
! forget_memory_reference (tree ref, tree *pre_p)
  {
!   /* Historically, the compiler has treated a bare reference to a volatile
!      lvalue as forcing a load.  */
!   if (TREE_THIS_VOLATILE (ref)
!       && COMPLETE_TYPE_P (TREE_TYPE (ref)))
!     {
!       tree type = TYPE_MAIN_VARIANT (TREE_TYPE (ref));
!       tree tmp = create_tmp_var (type, "vol");
!       add_statement (build2 (MODIFY_EXPR, type, tmp, ref), pre_p);
      }
  }
  
  /* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or IMAGPART_EXPR
*************** gimplify_conversion (tree *expr_p)
*** 1428,1440 ****
       *EXPR_P should be stored.
  
     POST_P points to the list where side effects that must happen after
!      *EXPR_P should be stored.  */
  
  static enum gimplify_status
  gimplify_compound_lval (tree *expr_p, tree *pre_p,
! 			tree *post_p, fallback_t fallback)
  {
!   tree *p;
    VEC(tree,heap) *stack;
    enum gimplify_status ret = GS_OK, tret;
    int i;
--- 1444,1458 ----
       *EXPR_P should be stored.
  
     POST_P points to the list where side effects that must happen after
!      *EXPR_P should be stored.
! 
!    WANT_VALUE is true if the value of the expression is needed.  */
  
  static enum gimplify_status
  gimplify_compound_lval (tree *expr_p, tree *pre_p,
! 			tree *post_p, bool want_value)
  {
!   tree *p, tmp;
    VEC(tree,heap) *stack;
    enum gimplify_status ret = GS_OK, tret;
    int i;
*************** gimplify_compound_lval (tree *expr_p, tr
*** 1479,1490 ****
  	     gimplified.  */
  	  if (!TREE_OPERAND (t, 2))
  	    {
! 	      tree low = unshare_expr (array_ref_low_bound (t));
  	      if (!is_gimple_min_invariant (low))
  		{
! 	          TREE_OPERAND (t, 2) = low;
! 		  tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
! 					is_gimple_formal_tmp_reg, fb_rvalue);
  		  ret = MIN (ret, tret);
  		}
  	    }
--- 1497,1509 ----
  	     gimplified.  */
  	  if (!TREE_OPERAND (t, 2))
  	    {
! 	      tree low = array_ref_low_bound (t);
! 
  	      if (!is_gimple_min_invariant (low))
  		{
! 		  low = unshare_expr (low);
! 		  tret = gimplify_to_operand (low, pre_p, post_p, &low, true);
! 		  TREE_OPERAND (t, 2) = low;
  		  ret = MIN (ret, tret);
  		}
  	    }
*************** gimplify_compound_lval (tree *expr_p, tr
*** 1492,1498 ****
  	  if (!TREE_OPERAND (t, 3))
  	    {
  	      tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)));
! 	      tree elmt_size = unshare_expr (array_ref_element_size (t));
  	      tree factor = size_int (TYPE_ALIGN_UNIT (elmt_type));
  
  	      /* Divide the element size by the alignment of the element
--- 1511,1517 ----
  	  if (!TREE_OPERAND (t, 3))
  	    {
  	      tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)));
! 	      tree elmt_size = array_ref_element_size (t);
  	      tree factor = size_int (TYPE_ALIGN_UNIT (elmt_type));
  
  	      /* Divide the element size by the alignment of the element
*************** gimplify_compound_lval (tree *expr_p, tr
*** 1501,1509 ****
  
  	      if (!is_gimple_min_invariant (elmt_size))
  		{
! 	          TREE_OPERAND (t, 3) = elmt_size;
! 		  tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p,
! 					is_gimple_formal_tmp_reg, fb_rvalue);
  		  ret = MIN (ret, tret);
  		}
  	    }
--- 1520,1529 ----
  
  	      if (!is_gimple_min_invariant (elmt_size))
  		{
! 		  elmt_size = unshare_expr (elmt_size);
! 		  tret = gimplify_to_operand (elmt_size, pre_p, post_p,
! 					      &elmt_size, true);
! 		  TREE_OPERAND (t, 3) = elmt_size;
  		  ret = MIN (ret, tret);
  		}
  	    }
*************** gimplify_compound_lval (tree *expr_p, tr
*** 1513,1519 ****
  	  /* Set the field offset into T and gimplify it.  */
  	  if (!TREE_OPERAND (t, 2))
  	    {
! 	      tree offset = unshare_expr (component_ref_field_offset (t));
  	      tree field = TREE_OPERAND (t, 1);
  	      tree factor
  		= size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT);
--- 1533,1539 ----
  	  /* Set the field offset into T and gimplify it.  */
  	  if (!TREE_OPERAND (t, 2))
  	    {
! 	      tree offset = component_ref_field_offset (t);
  	      tree field = TREE_OPERAND (t, 1);
  	      tree factor
  		= size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT);
*************** gimplify_compound_lval (tree *expr_p, tr
*** 1523,1531 ****
  
  	      if (!is_gimple_min_invariant (offset))
  		{
! 	          TREE_OPERAND (t, 2) = offset;
! 		  tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
! 					is_gimple_formal_tmp_reg, fb_rvalue);
  		  ret = MIN (ret, tret);
  		}
  	    }
--- 1543,1553 ----
  
  	      if (!is_gimple_min_invariant (offset))
  		{
! 		  offset = unshare_expr (offset);
! 		  tret = gimplify_to_operand (offset, pre_p, post_p,
! 					      &offset, true);
! 
! 		  TREE_OPERAND (t, 2) = offset;
  		  ret = MIN (ret, tret);
  		}
  	    }
*************** gimplify_compound_lval (tree *expr_p, tr
*** 1533,1539 ****
      }
  
    /* Step 2 is to gimplify the base expression.  */
!   tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval, fallback);
    ret = MIN (ret, tret);
  
    /* And finally, the indices and operands to BIT_FIELD_REF.  During this
--- 1555,1561 ----
      }
  
    /* Step 2 is to gimplify the base expression.  */
!   tret = gimplify_to_min_lval (*p, pre_p, post_p, p);
    ret = MIN (ret, tret);
  
    /* And finally, the indices and operands to BIT_FIELD_REF.  During this
*************** gimplify_compound_lval (tree *expr_p, tr
*** 1553,1572 ****
  	     exposes bugs in alias analysis.  The alias analyzer does
  	     not handle &PTR->FIELD very well.  Will fix after the
  	     branch is merged into mainline (dnovillo 2004-05-03).  */
! 	  if (!is_gimple_min_invariant (TREE_OPERAND (t, 1)))
  	    {
! 	      tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
! 				    is_gimple_formal_tmp_reg, fb_rvalue);
  	      ret = MIN (ret, tret);
  	    }
  	}
        else if (TREE_CODE (t) == BIT_FIELD_REF)
  	{
! 	  tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
! 				is_gimple_val, fb_rvalue);
  	  ret = MIN (ret, tret);
! 	  tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
! 				is_gimple_val, fb_rvalue);
  	  ret = MIN (ret, tret);
  	}
  
--- 1575,1598 ----
  	     exposes bugs in alias analysis.  The alias analyzer does
  	     not handle &PTR->FIELD very well.  Will fix after the
  	     branch is merged into mainline (dnovillo 2004-05-03).  */
! 	  tmp = TREE_OPERAND (t, 1);
! 	  if (!is_gimple_min_invariant (tmp))
  	    {
! 	      tret = gimplify_to_operand (tmp, pre_p, post_p, &tmp, true);
! 	      TREE_OPERAND (t, 1) = tmp;
  	      ret = MIN (ret, tret);
  	    }
  	}
        else if (TREE_CODE (t) == BIT_FIELD_REF)
  	{
! 	  tmp = TREE_OPERAND (t, 1);
! 	  tret = gimplify_to_operand (tmp, pre_p, post_p, &tmp, false);
! 	  TREE_OPERAND (t, 1) = tmp;
  	  ret = MIN (ret, tret);
! 
! 	  tmp = TREE_OPERAND (t, 2);
! 	  tret = gimplify_to_operand (tmp, pre_p, post_p, &tmp, false);
! 	  TREE_OPERAND (t, 2) = tmp;
  	  ret = MIN (ret, tret);
  	}
  
*************** gimplify_compound_lval (tree *expr_p, tr
*** 1578,1595 ****
        recalculate_side_effects (t);
      }
  
!   tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval, fallback);
!   ret = MIN (ret, tret);
  
!   /* If the outermost expression is a COMPONENT_REF, canonicalize its type.  */
!   if ((fallback & fb_rvalue) && TREE_CODE (*expr_p) == COMPONENT_REF)
      {
!       canonicalize_component_ref (expr_p);
!       ret = MIN (ret, GS_OK);
      }
  
-   VEC_free (tree, heap, stack);
- 
    return ret;
  }
  
--- 1604,1618 ----
        recalculate_side_effects (t);
      }
  
!   VEC_free (tree, heap, stack);
  
!   if (!want_value)
      {
!       if (ret == GS_ALL_DONE)
! 	forget_memory_reference (*expr_p, pre_p);
!       *expr_p = NULL_TREE;
      }
  
    return ret;
  }
  
*************** gimplify_self_mod_expr (tree *expr_p, tr
*** 1609,1615 ****
  			bool want_value)
  {
    enum tree_code code;
!   tree lhs, lvalue, rhs, t1;
    bool postfix;
    enum tree_code arith_code;
    enum gimplify_status ret;
--- 1632,1638 ----
  			bool want_value)
  {
    enum tree_code code;
!   tree lhs_op, lvalue, rhs, t1;
    bool postfix;
    enum tree_code arith_code;
    enum gimplify_status ret;
*************** gimplify_self_mod_expr (tree *expr_p, tr
*** 1634,1663 ****
  
    /* Gimplify the LHS into a GIMPLE lvalue.  */
    lvalue = TREE_OPERAND (*expr_p, 0);
!   ret = gimplify_expr (&lvalue, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
    if (ret == GS_ERROR)
      return ret;
  
    /* Extract the operands to the arithmetic operation.  */
!   lhs = lvalue;
!   rhs = TREE_OPERAND (*expr_p, 1);
! 
!   /* For postfix operator, we evaluate the LHS to an rvalue and then use
!      that as the result value and in the postqueue operation.  */
!   if (postfix)
!     {
!       ret = gimplify_expr (&lhs, pre_p, post_p, is_gimple_val, fb_rvalue);
!       if (ret == GS_ERROR)
! 	return ret;
!     }
  
!   t1 = build (arith_code, TREE_TYPE (*expr_p), lhs, rhs);
    t1 = build (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1);
  
    if (postfix)
      {
!       gimplify_and_add (t1, post_p);
!       *expr_p = lhs;
        return GS_ALL_DONE;
      }
    else
--- 1657,1682 ----
  
    /* Gimplify the LHS into a GIMPLE lvalue.  */
    lvalue = TREE_OPERAND (*expr_p, 0);
!   ret = gimplify_to_lhs (lvalue, pre_p, post_p, &lvalue);
    if (ret == GS_ERROR)
      return ret;
  
    /* Extract the operands to the arithmetic operation.  */
!   ret = gimplify_to_operand (lvalue, pre_p, post_p, &lhs_op, false);
!   if (ret == GS_ERROR)
!     return ret;
!   ret = gimplify_to_operand (TREE_OPERAND (*expr_p, 1), pre_p, post_p, &rhs,
! 			     false);
!   if (ret == GS_ERROR)
!     return ret;
  
!   t1 = build (arith_code, TREE_TYPE (*expr_p), lhs_op, rhs);
    t1 = build (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1);
  
    if (postfix)
      {
!       add_statement (t1, post_p);
!       *expr_p = lhs_op;
        return GS_ALL_DONE;
      }
    else
*************** maybe_with_size_expr (tree *expr_p)
*** 1698,1724 ****
  static enum gimplify_status
  gimplify_arg (tree *expr_p, tree *pre_p)
  {
!   bool (*test) (tree);
!   fallback_t fb;
  
    /* In general, we allow lvalues for function arguments to avoid
       extra overhead of copying large aggregates out of even larger
       aggregates into temporaries only to copy the temporaries to
       the argument list.  Make optimizers happy by pulling out to
!      temporaries those types that fit in registers.  */
!   if (is_gimple_reg_type (TREE_TYPE (*expr_p)))
!     test = is_gimple_val, fb = fb_rvalue;
!   else
!     test = is_gimple_lvalue, fb = fb_either;
! 
!   /* If this is a variable sized type, we must remember the size.  */
!   maybe_with_size_expr (expr_p);
  
!   /* There is a sequence point before a function call.  Side effects in
       the argument list must occur before the actual call. So, when
!      gimplifying arguments, force gimplify_expr to use an internal
       post queue which is then appended to the end of PRE_P.  */
!   return gimplify_expr (expr_p, pre_p, NULL, test, fb);
  }
  
  /* Gimplify the CALL_EXPR node pointed by EXPR_P.  PRE_P points to the
--- 1717,1753 ----
  static enum gimplify_status
  gimplify_arg (tree *expr_p, tree *pre_p)
  {
!   tree type = TREE_TYPE (*expr_p);
!   enum gimplify_status ret, tret;
! 
!   /* If this is a variable sized type, we must remember the size.  */
!   maybe_with_size_expr (expr_p);
  
    /* In general, we allow lvalues for function arguments to avoid
       extra overhead of copying large aggregates out of even larger
       aggregates into temporaries only to copy the temporaries to
       the argument list.  Make optimizers happy by pulling out to
!      temporaries those types that fit in registers.
  
!      There is a sequence point before a function call.  Side effects in
       the argument list must occur before the actual call. So, when
!      gimplifying arguments, force gimplify_main to use an internal
       post queue which is then appended to the end of PRE_P.  */
!   if (is_gimple_reg_type (type))
!     ret = gimplify_to_operand (*expr_p, pre_p, NULL, expr_p, false);
!   else
!     {
!       ret = gimplify_main (*expr_p, pre_p, NULL, expr_p, 0);
! 
!       if (!is_gimple_min_invariant (*expr_p)
! 	  && !is_gimple_lvalue (*expr_p))
! 	{
! 	  tret = gimplify_rhs_to_operand (*expr_p, pre_p, NULL, expr_p, false);
! 	  ret = MIN (ret, tret);
! 	}
!     }
! 
!   return ret;
  }
  
  /* Gimplify the CALL_EXPR node pointed by EXPR_P.  PRE_P points to the
*************** gimplify_call_expr (tree *expr_p, tree *
*** 1773,1798 ****
  	  if (!arglist || !TREE_CHAIN (arglist))
  	    {
  	      error ("too few arguments to function %<va_start%>");
! 	      *expr_p = build_empty_stmt ();
! 	      return GS_OK;
  	    }
  	  
  	  if (fold_builtin_next_arg (TREE_CHAIN (arglist)))
  	    {
! 	      *expr_p = build_empty_stmt ();
! 	      return GS_OK;
  	    }
  	  /* Avoid gimplifying the second argument to va_start, which needs
  	     to be the plain PARM_DECL.  */
! 	  return gimplify_arg (&TREE_VALUE (TREE_OPERAND (*expr_p, 1)), pre_p);
  	}
      }
  
    /* There is a sequence point before the call, so any side effects in
       the calling expression must occur before the actual call.  Force
!      gimplify_expr to use an internal post queue.  */
!   ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, NULL,
! 		       is_gimple_call_addr, fb_rvalue);
  
    if (PUSH_ARGS_REVERSED)
      TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1));
--- 1802,1837 ----
  	  if (!arglist || !TREE_CHAIN (arglist))
  	    {
  	      error ("too few arguments to function %<va_start%>");
! 	      *expr_p = NULL_TREE;
! 	      return GS_ALL_DONE;
  	    }
  	  
  	  if (fold_builtin_next_arg (TREE_CHAIN (arglist)))
  	    {
! 	      *expr_p = NULL_TREE;
! 	      return GS_ALL_DONE;
  	    }
  	  /* Avoid gimplifying the second argument to va_start, which needs
  	     to be the plain PARM_DECL.  */
! 	  ret = gimplify_arg (&TREE_VALUE (TREE_OPERAND (*expr_p, 1)), pre_p);
! 
! 	  if (ret == GS_ERROR)
! 	    return GS_ERROR;
! 
! 	  if (want_value)
! 	    return GS_ALL_DONE;
! 
! 	  add_statement (*expr_p, pre_p);
! 	  *expr_p = NULL_TREE;
! 	  return GS_ALL_DONE;
  	}
      }
  
    /* There is a sequence point before the call, so any side effects in
       the calling expression must occur before the actual call.  Force
!      gimplify_main to use an internal post queue.  */
!   ret = gimplify_to_call_addr (TREE_OPERAND (*expr_p, 0), pre_p, NULL,
! 			       &TREE_OPERAND (*expr_p, 0));
  
    if (PUSH_ARGS_REVERSED)
      TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1));
*************** gimplify_call_expr (tree *expr_p, tree *
*** 1833,1838 ****
--- 1872,1883 ----
        && (call_expr_flags (*expr_p) & (ECF_CONST | ECF_PURE)))
      TREE_SIDE_EFFECTS (*expr_p) = 0;
  
+   if (!want_value)
+     {
+       add_statement (*expr_p, pre_p);
+       *expr_p = NULL_TREE;
+     }
+ 
    return ret;
  }
  
*************** gimple_boolify (tree expr)
*** 2128,2161 ****
  	*EXPR_P should be stored.
  
     POST_P points to the list where side effects that must happen after
!      *EXPR_P should be stored.  */
  
  static enum gimplify_status
  gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target,
! 		    fallback_t fallback)
  {
    tree expr = *expr_p;
    tree tmp, tmp2, type;
    enum gimplify_status ret;
  
    type = TREE_TYPE (expr);
  
    /* If this COND_EXPR has a value, copy the values into a temporary within
       the arms.  */
!   if (! VOID_TYPE_P (type))
      {
        tree result;
  
        if (target)
  	{
! 	  ret = gimplify_expr (&target, pre_p, post_p,
! 			       is_gimple_min_lval, fb_lvalue);
  	  if (ret != GS_ERROR)
  	    ret = GS_OK;
  	  result = tmp = target;
  	  tmp2 = unshare_expr (target);
  	}
!       else if ((fallback & fb_lvalue) == 0)
  	{
  	  result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
  	  ret = GS_ALL_DONE;
--- 2173,2211 ----
  	*EXPR_P should be stored.
  
     POST_P points to the list where side effects that must happen after
!      *EXPR_P should be stored.
!      
!    WANT_VALUE is true if we need the value of *EXPR_P.  If WANT_LVALUE
!    is true, we also need the result to be a lvalue.  */
  
  static enum gimplify_status
  gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target,
! 		    bool want_value, bool want_lvalue)
  {
    tree expr = *expr_p;
    tree tmp, tmp2, type;
    enum gimplify_status ret;
  
+   if (!want_value && !target)
+     TREE_TYPE (*expr_p) = void_type_node;
+ 
    type = TREE_TYPE (expr);
  
    /* If this COND_EXPR has a value, copy the values into a temporary within
       the arms.  */
!   if (!VOID_TYPE_P (type))
      {
        tree result;
  
        if (target)
  	{
! 	  ret = gimplify_to_min_lval (target, pre_p, post_p, &target);
  	  if (ret != GS_ERROR)
  	    ret = GS_OK;
  	  result = tmp = target;
  	  tmp2 = unshare_expr (target);
  	}
!       else if (!want_lvalue)
  	{
  	  result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
  	  ret = GS_ALL_DONE;
*************** gimplify_cond_expr (tree *expr_p, tree *
*** 2174,2181 ****
  	  
  	  tmp2 = tmp = create_tmp_var (type, "iftmp");
  
! 	  expr = build (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0),
! 			TREE_OPERAND (expr, 1), TREE_OPERAND (expr, 2));
  
  	  result = build_fold_indirect_ref (tmp);
  	  ret = GS_ALL_DONE;
--- 2224,2231 ----
  	  
  	  tmp2 = tmp = create_tmp_var (type, "iftmp");
  
! 	  expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0),
! 			 TREE_OPERAND (expr, 1), TREE_OPERAND (expr, 2));
  
  	  result = build_fold_indirect_ref (tmp);
  	  ret = GS_ALL_DONE;
*************** gimplify_cond_expr (tree *expr_p, tree *
*** 2185,2207 ****
  	 if this branch is void; in C++ it can be, if it's a throw.  */
        if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
  	TREE_OPERAND (expr, 1)
! 	  = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 1));
  
        /* Build the else clause, 't1 = b;'.  */
        if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
  	TREE_OPERAND (expr, 2)
! 	  = build (MODIFY_EXPR, void_type_node, tmp2, TREE_OPERAND (expr, 2));
  
        TREE_TYPE (expr) = void_type_node;
        recalculate_side_effects (expr);
  
        /* Move the COND_EXPR to the prequeue.  */
!       gimplify_and_add (expr, pre_p);
  
        *expr_p = result;
        return ret;
      }
  
    /* Make sure the condition has BOOLEAN_TYPE.  */
    TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
  
--- 2235,2260 ----
  	 if this branch is void; in C++ it can be, if it's a throw.  */
        if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
  	TREE_OPERAND (expr, 1)
! 	  = build2 (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 1));
  
        /* Build the else clause, 't1 = b;'.  */
        if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
  	TREE_OPERAND (expr, 2)
! 	  = build2 (MODIFY_EXPR, void_type_node, tmp2, TREE_OPERAND (expr, 2));
  
        TREE_TYPE (expr) = void_type_node;
        recalculate_side_effects (expr);
  
        /* Move the COND_EXPR to the prequeue.  */
!       gimplify_to_void (expr, pre_p);
  
        *expr_p = result;
        return ret;
      }
  
+   gcc_assert (!want_value);
+   gcc_assert (!target);
+ 
    /* Make sure the condition has BOOLEAN_TYPE.  */
    TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
  
*************** gimplify_cond_expr (tree *expr_p, tree *
*** 2213,2235 ****
  
        if (expr != *expr_p)
  	{
! 	  *expr_p = expr;
  
! 	  /* We can't rely on gimplify_expr to re-gimplify the expanded
  	     form properly, as cleanups might cause the target labels to be
  	     wrapped in a TRY_FINALLY_EXPR.  To prevent that, we need to
  	     set up a conditional context.  */
  	  gimple_push_condition ();
! 	  gimplify_stmt (expr_p);
  	  gimple_pop_condition (pre_p);
  
  	  return GS_ALL_DONE;
  	}
      }
  
    /* Now do the normal gimplification.  */
!   ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
! 		       is_gimple_condexpr, fb_rvalue);
  
    gimple_push_condition ();
  
--- 2266,2290 ----
  
        if (expr != *expr_p)
  	{
! 	  tree stmts = NULL;
  
! 	  /* We can't rely on gimplify_main to re-gimplify the expanded
  	     form properly, as cleanups might cause the target labels to be
  	     wrapped in a TRY_FINALLY_EXPR.  To prevent that, we need to
  	     set up a conditional context.  */
  	  gimple_push_condition ();
! 	  gimplify_to_void (expr, &stmts);
  	  gimple_pop_condition (pre_p);
+ 	  add_statement (stmts, pre_p);
  
+ 	  *expr_p = NULL_TREE;
  	  return GS_ALL_DONE;
  	}
      }
  
    /* Now do the normal gimplification.  */
!   ret = gimplify_to_condexpr (TREE_OPERAND (expr, 0), pre_p, NULL,
! 			      &TREE_OPERAND (expr, 0));
  
    gimple_push_condition ();
  
*************** gimplify_cond_expr (tree *expr_p, tree *
*** 2242,2264 ****
    if (ret == GS_ERROR)
      ;
    else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
!     ret = GS_ALL_DONE;
    else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2)))
      /* Rewrite "if (a); else b" to "if (!a) b"  */
      {
        TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0));
!       ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
! 			   is_gimple_condexpr, fb_rvalue);
  
        tmp = TREE_OPERAND (expr, 1);
        TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 2);
        TREE_OPERAND (expr, 2) = tmp;
      }
    else
!     /* Both arms are empty; replace the COND_EXPR with its predicate.  */
!     expr = TREE_OPERAND (expr, 0);
  
!   *expr_p = expr;
    return ret;
  }
  
--- 2297,2326 ----
    if (ret == GS_ERROR)
      ;
    else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
!     {
!       add_statement (expr, pre_p);
!       ret = GS_ALL_DONE;
!     }
    else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2)))
      /* Rewrite "if (a); else b" to "if (!a) b"  */
      {
        TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0));
!       ret = gimplify_to_condexpr (TREE_OPERAND (expr, 0), pre_p, NULL,
! 				  &TREE_OPERAND (expr, 0));
  
        tmp = TREE_OPERAND (expr, 1);
        TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 2);
        TREE_OPERAND (expr, 2) = tmp;
+       add_statement (expr, pre_p);
+       ret = GS_ALL_DONE;
      }
    else
!     {
!       /* Otherwise, condition is a no-op.  */
!       ret = GS_ALL_DONE;
!     }
  
!   *expr_p = NULL_TREE;
    return ret;
  }
  
*************** gimplify_init_ctor_preeval (tree *expr_p
*** 2404,2415 ****
       gimplification now means that we won't have to deal with complicated
       language-specific trees, nor trees like SAVE_EXPR that can induce
       exponential search behavior.  */
!   one = gimplify_expr (expr_p, pre_p, post_p, is_gimple_mem_rhs, fb_rvalue);
    if (one == GS_ERROR)
      {
        *expr_p = NULL;
        return;
      }
  
    /* If we gimplified to a bare decl, we can be sure that it doesn't overlap
       with the lhs, since "a = { .x=a }" doesn't make sense.  This will
--- 2466,2479 ----
       gimplification now means that we won't have to deal with complicated
       language-specific trees, nor trees like SAVE_EXPR that can induce
       exponential search behavior.  */
!   one = gimplify_to_rhs (*expr_p, pre_p, post_p, expr_p);
    if (one == GS_ERROR)
      {
        *expr_p = NULL;
        return;
      }
+   if (!is_gimple_mem_rhs (*expr_p))
+     gimplify_rhs_to_operand (*expr_p, pre_p, post_p, expr_p, false);
  
    /* If we gimplified to a bare decl, we can be sure that it doesn't overlap
       with the lhs, since "a = { .x=a }" doesn't make sense.  This will
*************** gimplify_init_ctor_eval_range (tree obje
*** 2466,2475 ****
    /* Create and initialize the index variable.  */
    var_type = TREE_TYPE (upper);
    var = create_tmp_var (var_type, NULL);
!   append_to_statement_list (build2 (MODIFY_EXPR, var_type, var, lower), pre_p);
  
    /* Add the loop entry label.  */
!   append_to_statement_list (build1 (LABEL_EXPR,
  				    void_type_node,
  				    loop_entry_label),
  			    pre_p);
--- 2530,2539 ----
    /* Create and initialize the index variable.  */
    var_type = TREE_TYPE (upper);
    var = create_tmp_var (var_type, NULL);
!   add_statement (build2 (MODIFY_EXPR, var_type, var, lower), pre_p);
  
    /* Add the loop entry label.  */
!   add_statement (build1 (LABEL_EXPR,
  				    void_type_node,
  				    loop_entry_label),
  			    pre_p);
*************** gimplify_init_ctor_eval_range (tree obje
*** 2487,2498 ****
      gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
  			     pre_p, cleared);
    else
!     append_to_statement_list (build2 (MODIFY_EXPR, TREE_TYPE (cref),
  				      cref, value),
  			      pre_p);
  
    /* We exit the loop when the index var is equal to the upper bound.  */
!   gimplify_and_add (build3 (COND_EXPR, void_type_node,
  			    build2 (EQ_EXPR, boolean_type_node,
  				    var, upper),
  			    build1 (GOTO_EXPR,
--- 2551,2562 ----
      gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
  			     pre_p, cleared);
    else
!     add_statement (build2 (MODIFY_EXPR, TREE_TYPE (cref),
  				      cref, value),
  			      pre_p);
  
    /* We exit the loop when the index var is equal to the upper bound.  */
!   gimplify_to_void (build3 (COND_EXPR, void_type_node,
  			    build2 (EQ_EXPR, boolean_type_node,
  				    var, upper),
  			    build1 (GOTO_EXPR,
*************** gimplify_init_ctor_eval_range (tree obje
*** 2502,2521 ****
  		    pre_p);
  
    /* Otherwise, increment the index var...  */
!   append_to_statement_list (build2 (MODIFY_EXPR, var_type, var,
  				    build2 (PLUS_EXPR, var_type, var,
  					    fold_convert (var_type,
  							  integer_one_node))),
  			    pre_p);
  
    /* ...and jump back to the loop entry.  */
!   append_to_statement_list (build1 (GOTO_EXPR,
  				    void_type_node,
  				    loop_entry_label),
  			    pre_p);
  
    /* Add the loop exit label.  */
!   append_to_statement_list (build1 (LABEL_EXPR,
  				    void_type_node,
  				    loop_exit_label),
  			    pre_p);
--- 2566,2585 ----
  		    pre_p);
  
    /* Otherwise, increment the index var...  */
!   add_statement (build2 (MODIFY_EXPR, var_type, var,
  				    build2 (PLUS_EXPR, var_type, var,
  					    fold_convert (var_type,
  							  integer_one_node))),
  			    pre_p);
  
    /* ...and jump back to the loop entry.  */
!   add_statement (build1 (GOTO_EXPR,
  				    void_type_node,
  				    loop_entry_label),
  			    pre_p);
  
    /* Add the loop exit label.  */
!   add_statement (build1 (LABEL_EXPR,
  				    void_type_node,
  				    loop_exit_label),
  			    pre_p);
*************** gimplify_init_ctor_eval (tree object, VE
*** 2601,2607 ****
        else
  	{
  	  init = build (MODIFY_EXPR, TREE_TYPE (cref), cref, value);
! 	  gimplify_and_add (init, pre_p);
  	}
      }
  }
--- 2665,2671 ----
        else
  	{
  	  init = build (MODIFY_EXPR, TREE_TYPE (cref), cref, value);
! 	  gimplify_to_void (init, pre_p);
  	}
      }
  }
*************** gimplify_init_constructor (tree *expr_p,
*** 2626,2633 ****
    if (TREE_CODE (ctor) != CONSTRUCTOR)
      return GS_UNHANDLED;
  
!   ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 		       is_gimple_lvalue, fb_lvalue);
    if (ret == GS_ERROR)
      return ret;
    object = TREE_OPERAND (*expr_p, 0);
--- 2690,2697 ----
    if (TREE_CODE (ctor) != CONSTRUCTOR)
      return GS_UNHANDLED;
  
!   ret = gimplify_to_lhs (TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			 &TREE_OPERAND (*expr_p, 0));
    if (ret == GS_ERROR)
      return ret;
    object = TREE_OPERAND (*expr_p, 0);
*************** gimplify_init_constructor (tree *expr_p,
*** 2764,2771 ****
  	       case of variable sized types.  Avoid shared tree structures.  */
  	    CONSTRUCTOR_ELTS (ctor) = NULL;
  	    object = unshare_expr (object);
! 	    gimplify_stmt (expr_p);
! 	    append_to_statement_list (*expr_p, pre_p);
  	  }
  
  	/* If we have not block cleared the object, or if there are nonzero
--- 2828,2834 ----
  	       case of variable sized types.  Avoid shared tree structures.  */
  	    CONSTRUCTOR_ELTS (ctor) = NULL;
  	    object = unshare_expr (object);
! 	    gimplify_to_void (*expr_p, pre_p);
  	  }
  
  	/* If we have not block cleared the object, or if there are nonzero
*************** gimplify_init_constructor (tree *expr_p,
*** 2778,2785 ****
  	      preeval_data.lhs_base_decl = NULL;
  	    preeval_data.lhs_alias_set = get_alias_set (object);
  
! 	    gimplify_init_ctor_preeval (&TREE_OPERAND (*expr_p, 1),
! 					pre_p, post_p, &preeval_data);
  	    gimplify_init_ctor_eval (object, elts, pre_p, cleared);
  	  }
  
--- 2841,2847 ----
  	      preeval_data.lhs_base_decl = NULL;
  	    preeval_data.lhs_alias_set = get_alias_set (object);
  
! 	    gimplify_init_ctor_preeval (&ctor, pre_p, post_p, &preeval_data);
  	    gimplify_init_ctor_eval (object, elts, pre_p, cleared);
  	  }
  
*************** gimplify_init_constructor (tree *expr_p,
*** 2815,2823 ****
  	  {
  	    ctor = build (COMPLEX_EXPR, type, r, i);
  	    TREE_OPERAND (*expr_p, 1) = ctor;
! 	    ret = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
! 				 rhs_predicate_for (TREE_OPERAND (*expr_p, 0)),
! 				 fb_rvalue);
  	  }
        }
        break;
--- 2877,2886 ----
  	  {
  	    ctor = build (COMPLEX_EXPR, type, r, i);
  	    TREE_OPERAND (*expr_p, 1) = ctor;
! 	    ret = gimplify_to_assignment_rhs (TREE_OPERAND (*expr_p, 1),
! 					      pre_p, post_p,
! 					      &TREE_OPERAND (*expr_p, 1),
! 					      TREE_OPERAND (*expr_p, 0));
  	  }
        }
        break;
*************** gimplify_init_constructor (tree *expr_p,
*** 2855,2862 ****
  	for (ix = 0; VEC_iterate (constructor_elt, elts, ix, ce); ix++)
  	  {
  	    enum gimplify_status tret;
! 	    tret = gimplify_expr (&ce->value, pre_p, post_p,
! 				  is_gimple_val, fb_rvalue);
  	    if (tret == GS_ERROR)
  	      ret = GS_ERROR;
  	  }
--- 2918,2925 ----
  	for (ix = 0; VEC_iterate (constructor_elt, elts, ix, ce); ix++)
  	  {
  	    enum gimplify_status tret;
! 	    tret = gimplify_to_operand (ce->value, pre_p, post_p,
! 					&ce->value, false);
  	    if (tret == GS_ERROR)
  	      ret = GS_ERROR;
  	  }
*************** gimplify_init_constructor (tree *expr_p,
*** 2870,2883 ****
  
    if (ret == GS_ERROR)
      return GS_ERROR;
!   else if (want_value)
      {
!       append_to_statement_list (*expr_p, pre_p);
!       *expr_p = object;
!       return GS_OK;
      }
-   else
-     return GS_ALL_DONE;
  }
  
  /* Given a pointer value OP0, return a simplified version of an
--- 2933,2951 ----
  
    if (ret == GS_ERROR)
      return GS_ERROR;
! 
!   add_statement (*expr_p, pre_p);
! 
!   if (want_value)
!    {
!      *expr_p = object;
!      return GS_OK;
!    }
!   else
      {
!       *expr_p = NULL_TREE;
!       return GS_ALL_DONE;
      }
  }
  
  /* Given a pointer value OP0, return a simplified version of an
*************** gimplify_modify_expr_rhs (tree *expr_p, 
*** 2997,3003 ****
        case COMPOUND_EXPR:
  	/* Remove any COMPOUND_EXPR in the RHS so the following cases will be
  	   caught.  */
! 	gimplify_compound_expr (from_p, pre_p, true);
  	ret = GS_OK;
  	break;
  
--- 3065,3071 ----
        case COMPOUND_EXPR:
  	/* Remove any COMPOUND_EXPR in the RHS so the following cases will be
  	   caught.  */
! 	gimplify_compound_expr (from_p, pre_p, post_p, true);
  	ret = GS_OK;
  	break;
  
*************** gimplify_modify_expr_rhs (tree *expr_p, 
*** 3015,3024 ****
  	  {
  	    *expr_p = *from_p;
  	    return gimplify_cond_expr (expr_p, pre_p, post_p, *to_p,
! 				       fb_rvalue);
  	  }
! 	else
! 	  ret = GS_UNHANDLED;
  	break;
  
        case CALL_EXPR:
--- 3083,3092 ----
  	  {
  	    *expr_p = *from_p;
  	    return gimplify_cond_expr (expr_p, pre_p, post_p, *to_p,
! 				       false, false);
  	  }
! 
! 	ret = GS_UNHANDLED;
  	break;
  
        case CALL_EXPR:
*************** gimplify_modify_expr_complex_part (tree 
*** 3099,3110 ****
  
    TREE_OPERAND (*expr_p, 0) = lhs;
    TREE_OPERAND (*expr_p, 1) = new_rhs;
  
!   if (want_value)
!     {
!       append_to_statement_list (*expr_p, pre_p);
!       *expr_p = rhs;
!     }
  
    return GS_ALL_DONE;
  }
--- 3167,3176 ----
  
    TREE_OPERAND (*expr_p, 0) = lhs;
    TREE_OPERAND (*expr_p, 1) = new_rhs;
+   TREE_TYPE (*expr_p) = TREE_TYPE (lhs);
  
!   add_statement (*expr_p, pre_p);
!   *expr_p = (want_value ? rhs : NULL_TREE);
  
    return GS_ALL_DONE;
  }
*************** gimplify_modify_expr (tree *expr_p, tree
*** 3152,3163 ****
       that is what we must here.  */
    maybe_with_size_expr (from_p);
  
!   ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
    if (ret == GS_ERROR)
      return ret;
  
!   ret = gimplify_expr (from_p, pre_p, post_p,
! 		       rhs_predicate_for (*to_p), fb_rvalue);
    if (ret == GS_ERROR)
      return ret;
  
--- 3218,3228 ----
       that is what we must here.  */
    maybe_with_size_expr (from_p);
  
!   ret = gimplify_to_lhs (*to_p, pre_p, post_p, to_p);
    if (ret == GS_ERROR)
      return ret;
  
!   ret = gimplify_to_assignment_rhs (*from_p, pre_p, post_p, from_p, *to_p);
    if (ret == GS_ERROR)
      return ret;
  
*************** gimplify_modify_expr (tree *expr_p, tree
*** 3200,3212 ****
        *to_p = make_ssa_name (*to_p, *expr_p);
      }
  
!   if (want_value)
!     {
!       append_to_statement_list (*expr_p, pre_p);
!       *expr_p = *to_p;
!       return GS_OK;
!     }
! 
    return GS_ALL_DONE;
  }
  
--- 3265,3272 ----
        *to_p = make_ssa_name (*to_p, *expr_p);
      }
  
!   add_statement (*expr_p, pre_p);
!   *expr_p = want_value ? *to_p : NULL_TREE;
    return GS_ALL_DONE;
  }
  
*************** gimplify_modify_expr (tree *expr_p, tree
*** 3214,3220 ****
      with a call to BUILT_IN_MEMCMP.  */
  
  static enum gimplify_status
! gimplify_variable_sized_compare (tree *expr_p)
  {
    tree op0 = TREE_OPERAND (*expr_p, 0);
    tree op1 = TREE_OPERAND (*expr_p, 1);
--- 3274,3282 ----
      with a call to BUILT_IN_MEMCMP.  */
  
  static enum gimplify_status
! gimplify_variable_sized_compare (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED,
! 				 tree *post_p ATTRIBUTE_UNUSED,
! 				 bool want_value ATTRIBUTE_UNUSED)
  {
    tree op0 = TREE_OPERAND (*expr_p, 0);
    tree op1 = TREE_OPERAND (*expr_p, 1);
*************** gimplify_variable_sized_compare (tree *e
*** 3249,3398 ****
  	*EXPR_P should be stored.  */
  
  static enum gimplify_status
! gimplify_boolean_expr (tree *expr_p)
  {
    /* Preserve the original type of the expression.  */
    tree type = TREE_TYPE (*expr_p);
  
!   *expr_p = build (COND_EXPR, type, *expr_p,
! 		   convert (type, boolean_true_node),
! 		   convert (type, boolean_false_node));
  
    return GS_OK;
  }
  
! /* Gimplifies an expression sequence.  This function gimplifies each
!    expression and re-writes the original expression with the last
!    expression of the sequence in GIMPLE form.
! 
!    PRE_P points to the list where the side effects for all the
!        expressions in the sequence will be emitted.
! 
!    WANT_VALUE is true when the result of the last COMPOUND_EXPR is used.  */
! /* ??? Should rearrange to share the pre-queue with all the indirect
!    invocations of gimplify_expr.  Would probably save on creations
!    of statement_list nodes.  */
  
  static enum gimplify_status
! gimplify_compound_expr (tree *expr_p, tree *pre_p, bool want_value)
  {
!   tree t = *expr_p;
  
!   do
      {
!       tree *sub_p = &TREE_OPERAND (t, 0);
! 
!       if (TREE_CODE (*sub_p) == COMPOUND_EXPR)
! 	gimplify_compound_expr (sub_p, pre_p, false);
!       else
! 	gimplify_stmt (sub_p);
!       append_to_statement_list (*sub_p, pre_p);
! 
!       t = TREE_OPERAND (t, 1);
!     }
!   while (TREE_CODE (t) == COMPOUND_EXPR);
  
-   *expr_p = t;
-   if (want_value)
-     return GS_OK;
-   else
-     {
-       gimplify_stmt (expr_p);
        return GS_ALL_DONE;
      }
  }
  
! /* Gimplifies a statement list.  These may be created either by an
!    enlightened front-end, or by shortcut_cond_expr.  */
  
  static enum gimplify_status
! gimplify_statement_list (tree *expr_p)
  {
!   tree_stmt_iterator i = tsi_start (*expr_p);
  
!   while (!tsi_end_p (i))
      {
!       tree t;
! 
!       gimplify_stmt (tsi_stmt_ptr (i));
! 
!       t = tsi_stmt (i);
!       if (t == NULL)
! 	tsi_delink (&i);
!       else if (TREE_CODE (t) == STATEMENT_LIST)
! 	{
! 	  tsi_link_before (&i, t, TSI_SAME_STMT);
! 	  tsi_delink (&i);
! 	}
!       else
! 	tsi_next (&i);
      }
  
!   return GS_ALL_DONE;
  }
  
! /*  Gimplify a SAVE_EXPR node.  EXPR_P points to the expression to
!     gimplify.  After gimplification, EXPR_P will point to a new temporary
!     that holds the original value of the SAVE_EXPR node.
! 
!     PRE_P points to the list where side effects that must happen before
! 	*EXPR_P should be stored.  */
  
  static enum gimplify_status
! gimplify_save_expr (tree *expr_p, tree *pre_p, tree *post_p)
  {
!   enum gimplify_status ret = GS_ALL_DONE;
!   tree val;
  
!   gcc_assert (TREE_CODE (*expr_p) == SAVE_EXPR);
!   val = TREE_OPERAND (*expr_p, 0);
  
!   /* If the SAVE_EXPR has not been resolved, then evaluate it once.  */
!   if (!SAVE_EXPR_RESOLVED_P (*expr_p))
!     {
!       /* The operand may be a void-valued expression such as SAVE_EXPRs
! 	 generated by the Java frontend for class initialization.  It is
! 	 being executed only for its side-effects.  */
!       if (TREE_TYPE (val) == void_type_node)
! 	{
! 	  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			       is_gimple_stmt, fb_none);
! 	  append_to_statement_list (TREE_OPERAND (*expr_p, 0), pre_p);
! 	  val = NULL;
! 	}
!       else
! 	val = get_initialized_tmp_var (val, pre_p, post_p);
  
!       TREE_OPERAND (*expr_p, 0) = val;
!       SAVE_EXPR_RESOLVED_P (*expr_p) = 1;
      }
  
!   *expr_p = val;
  
!   return ret;
! }
  
! /*  Re-write the ADDR_EXPR node pointed by EXPR_P
  
!       unary_expr
! 	      : ...
! 	      | '&' varname
! 	      ...
  
!     PRE_P points to the list where side effects that must happen before
! 	*EXPR_P should be stored.
  
!     POST_P points to the list where side effects that must happen after
! 	*EXPR_P should be stored.  */
  
! static enum gimplify_status
! gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
! {
!   tree expr = *expr_p;
!   tree op0 = TREE_OPERAND (expr, 0);
!   enum gimplify_status ret;
  
!   switch (TREE_CODE (op0))
      {
      case INDIRECT_REF:
      case MISALIGNED_INDIRECT_REF:
--- 3311,3803 ----
  	*EXPR_P should be stored.  */
  
  static enum gimplify_status
! gimplify_boolean_expr (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED,
! 		       tree *post_p ATTRIBUTE_UNUSED,
! 		       bool want_value ATTRIBUTE_UNUSED)
  {
    /* Preserve the original type of the expression.  */
    tree type = TREE_TYPE (*expr_p);
  
!   *expr_p = build3 (COND_EXPR, type, *expr_p,
! 		    convert (type, boolean_true_node),
! 		    convert (type, boolean_false_node));
  
    return GS_OK;
  }
  
! /* Gimplify constructor *EXPR_P, appending new statements to PRE_P and
!    POST_P queues.  If WANT_VALUE is true, value of the expression is
!    needed.  */
  
  static enum gimplify_status
! gimplify_constructor (tree *expr_p, tree *pre_p,
! 		      tree *post_p ATTRIBUTE_UNUSED, bool want_value)
  {
!   tree tmp, type;
  
!   if (!want_value)
      {
!       unsigned HOST_WIDE_INT ix;
!       constructor_elt *ce;
!       for (ix = 0;
! 	   VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (*expr_p), ix, ce);
! 	   ix++)
! 	gimplify_to_void (ce->value, pre_p);
!       *expr_p = NULL_TREE;
  
        return GS_ALL_DONE;
      }
+ 
+   /* Let gimplify_modify_expr handle this.  */
+   type = TREE_TYPE (*expr_p);
+   tmp = create_tmp_var (type, get_name (*expr_p));
+   *expr_p = build2 (MODIFY_EXPR, type, tmp, *expr_p);
+ 
+   return GS_OK;
  }
  
! /* Gimplify unary expression *EXPR_P, appending new statements to PRE_P and
!    POST_P queues.  If WANT_VALUE is true, value of the expression is
!    needed.  */
  
  static enum gimplify_status
! gimplify_unary_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
  {
!   enum gimplify_status ret;
!   tree op0 = TREE_OPERAND (*expr_p, 0);
  
!   if (want_value)
      {
!       ret = gimplify_to_operand (op0, pre_p, post_p,
! 				 &TREE_OPERAND (*expr_p, 0), false);
!       recalculate_side_effects (*expr_p);
!       return ret;
      }
  
!   *expr_p = NULL_TREE;
!   return gimplify_to_void (op0, pre_p);
  }
  
! /* Gimplify indirect_ref expression *EXPR_P, appending new statements to PRE_P
!    and POST_P queues.  If WANT_VALUE is true, value of the expression is
!    needed.  */
  
  static enum gimplify_status
! gimplify_indirect_ref (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
  {
!   enum gimplify_status ret;
!   tree op0 = TREE_OPERAND (*expr_p, 0);
  
!   if (want_value
!       /* We must preserve volatile loads even if the value is not needed.  */
!       || TREE_THIS_VOLATILE (*expr_p))
!     {
!       ret = gimplify_to_operand (op0, pre_p, post_p,
! 				 &TREE_OPERAND (*expr_p, 0), false);
!       recalculate_side_effects (*expr_p);
!       if (want_value)
! 	return ret;
  
!       if (ret == GS_ALL_DONE)
! 	forget_memory_reference (*expr_p, pre_p);
  
!       *expr_p = NULL_TREE;
!       return ret;
!     }
!   else
!     {
!       *expr_p = NULL_TREE;
!       return gimplify_to_void (op0, pre_p);
      }
+ }
  
! /* *EXPR_P is a NOP_EXPR or CONVERT_EXPR.  Remove it and/or other conversions
!    underneath as appropriate.  */
  
! static enum gimplify_status
! gimplify_conversion (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED,
! 		     tree *post_p ATTRIBUTE_UNUSED,
! 		     bool want_value)
! {
!   tree old_expr = *expr_p;
  
!   gcc_assert (TREE_CODE (*expr_p) == NOP_EXPR
! 	      || TREE_CODE (*expr_p) == CONVERT_EXPR);
  
!   if (IS_EMPTY_STMT (*expr_p))
!     {
!       gcc_assert (!want_value);
!       *expr_p = NULL_TREE;
!       return GS_ALL_DONE;
!     }
  
!   if (VOID_TYPE_P (TREE_TYPE (*expr_p)) || !want_value)
!     {
!       /* Just strip a conversion to void (or in void context) and
! 	 try again.  */
!       *expr_p = TREE_OPERAND (*expr_p, 0);
!       return GS_OK;
!     }
  
!   /* Then strip away all but the outermost conversion.  */
!   STRIP_SIGN_NOPS (TREE_OPERAND (*expr_p, 0));
  
!   /* And remove the outermost conversion if it's useless.  */
!   if (tree_ssa_useless_type_conversion (*expr_p))
!     *expr_p = TREE_OPERAND (*expr_p, 0);
  
!   /* If we still have a conversion at the toplevel,
!      then canonicalize some constructs.  */
!   if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
!     {
!       tree sub = TREE_OPERAND (*expr_p, 0);
! 
!       /* If a NOP conversion is changing the type of a COMPONENT_REF
! 	 expression, then canonicalize its type now in order to expose more
! 	 redundant conversions.  */
!       if (TREE_CODE (sub) == COMPONENT_REF)
! 	canonicalize_component_ref (&TREE_OPERAND (*expr_p, 0));
! 
!       /* If a NOP conversion is changing a pointer to array of foo
! 	 to a pointer to foo, embed that change in the ADDR_EXPR.  */
!       else if (TREE_CODE (sub) == ADDR_EXPR)
! 	canonicalize_addr_expr (expr_p);
!     }
! 
!   if (*expr_p != old_expr)
!     return GS_OK;
! 
!   return gimplify_unary_expr (expr_p, pre_p, post_p, want_value);
! }
! 
! /* Gimplify binary expression *EXPR_P, appending new statements to PRE_P and
!    POST_P queues.  If WANT_VALUE is true, value of the expression is
!    needed.  */
! 
! static enum gimplify_status
! gimplify_binary_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
! {
!   enum gimplify_status ret, tret;
!   tree op0 = TREE_OPERAND (*expr_p, 0);
!   tree op1 = TREE_OPERAND (*expr_p, 1);
! 
!   if (want_value)
!     {
!       ret = gimplify_to_operand (op0, pre_p, post_p,
! 				 &TREE_OPERAND (*expr_p, 0), false);
!       tret = gimplify_to_operand (op1, pre_p, post_p,
! 				  &TREE_OPERAND (*expr_p, 1), false);
!       ret = MIN (ret, tret);
!       recalculate_side_effects (*expr_p);
!       return ret;
!     }
! 
!   *expr_p = NULL_TREE;
!   ret = gimplify_to_void (op0, pre_p);
!   tret = gimplify_to_void (op1, pre_p);
!   ret = MIN (ret, tret);
!   return ret;
! }
! 
! /* Gimplify const_decl expression *EXPR_P, appending new statements to PRE_P
!    and POST_P queues.  If WANT_VALUE is true, value of the expression is
!    needed.
!    
!    If WANT_LVALUE is true, address of the const_decl is taken and thus we
!    cannot replace it by the value of the constant.  This happens when constant
!    is passed as an argument in fortran (call by reference).  ??? Maybe force
!    the constant to temporary variable in this case?  */
! 
! static enum gimplify_status
! gimplify_const_decl (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED,
! 		     tree *post_p ATTRIBUTE_UNUSED, bool want_value,
! 		     bool want_lvalue)
! {
!   if (!want_value)
!     *expr_p = NULL_TREE;
!   else if (!want_lvalue)
!     *expr_p = DECL_INITIAL (*expr_p);
! 
!   return GS_ALL_DONE;
! }
! 
! /* Gimplify goto expression *EXPR_P, appending new statements to PRE_P.  */
! 
! static enum gimplify_status
! gimplify_goto_expr (tree *expr_p, tree *pre_p)
! {
!   tree lab = GOTO_DESTINATION (*expr_p);
!   static enum gimplify_status ret = GS_ALL_DONE;
! 
!   /* If the target is not LABEL, then it is a computed jump
!      and it needs to be gimplified.  */
!   if (TREE_CODE (lab) != LABEL_DECL)
!     ret = gimplify_to_operand (lab, pre_p, NULL, &GOTO_DESTINATION (*expr_p),
! 			       false);
! 
!   add_statement (*expr_p, pre_p);
!   *expr_p = NULL_TREE;
! 
!   return ret;
! }
! 
! /* Gimplify label expression *EXPR_P, appending new statements to PRE_P.  */
! 
! static enum gimplify_status
! gimplify_label_expr (tree *expr_p, tree *pre_p)
! {
!   gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p))
! 	      == current_function_decl);
!   add_statement (*expr_p, pre_p);
!   *expr_p = NULL_TREE;
!   return GS_ALL_DONE;
! }
! 
! /* Gimplify try-finally expression *EXPR_P, appending new statements to PRE_P.  */
! 
! static enum gimplify_status
! gimplify_try_finally_expr (tree *expr_p, tree *pre_p)
! {
!   gimplify_to_stmt_list (&TREE_OPERAND (*expr_p, 0));
!   gimplify_to_stmt_list (&TREE_OPERAND (*expr_p, 1));
! 
!   add_statement (*expr_p, pre_p);
!   *expr_p = NULL_TREE;
!   return GS_ALL_DONE;
! }
! 
! /* Gimplify try-catch expression *EXPR_P, appending new statements to PRE_P.  */
! 
! static enum gimplify_status
! gimplify_try_catch_expr (tree *expr_p, tree *pre_p)
! {
!   gimplify_to_stmt_list (&TREE_OPERAND (*expr_p, 0));
!   gimplify_to_stmt_list (&TREE_OPERAND (*expr_p, 1));
! 
!   add_statement (*expr_p, pre_p);
!   *expr_p = NULL_TREE;
!   return GS_ALL_DONE;
! }
! 
! /* Gimplify catch expression *EXPR_P, appending new statements to PRE_P.  */
! 
! static enum gimplify_status
! gimplify_catch_expr (tree *expr_p, tree *pre_p)
! {
!   gimplify_to_stmt_list (&CATCH_BODY (*expr_p));
! 
!   add_statement (*expr_p, pre_p);
!   *expr_p = NULL_TREE;
!   return GS_ALL_DONE;
! }
! 
! /* Gimplify eh_filter expression *EXPR_P, appending new statements to PRE_P.  */
! 
! static enum gimplify_status
! gimplify_eh_filter_expr (tree *expr_p, tree *pre_p)
! {
!   gimplify_to_stmt_list (&EH_FILTER_FAILURE (*expr_p));
! 
!   add_statement (*expr_p, pre_p);
!   *expr_p = NULL_TREE;
!   return GS_ALL_DONE;
! }
! 
! /* Gimplify obj_type_ref expression *EXPR_P, appending new statements to PRE_P
!    and POST_P queues.  If WANT_VALUE is true, value of the expression is
!    needed.  */
! 
! static enum gimplify_status
! gimplify_obj_type_ref (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
! {
!   enum gimplify_status ret, tret;
!   tree obj = OBJ_TYPE_REF_OBJECT (*expr_p);
!   tree expr = OBJ_TYPE_REF_EXPR (*expr_p);
! 
!   if (want_value)
!     {
!       ret = gimplify_to_operand (obj, pre_p, NULL,
! 				 &OBJ_TYPE_REF_OBJECT (*expr_p), false);
!       tret = gimplify_to_operand (expr, pre_p, post_p,
! 				  &OBJ_TYPE_REF_EXPR (*expr_p), false);
!       ret = MIN (ret, tret);
!       recalculate_side_effects (*expr_p);
!       return ret;
!     }
! 
!   *expr_p = NULL_TREE;
!   ret = gimplify_to_void (obj, pre_p);
!   tret = gimplify_to_void (expr, pre_p);
!   ret = MIN (ret, tret);
!   return ret;
! }
! 
! /* Gimplifies an expression sequence.  This function gimplifies each
!    expression and re-writes the original expression with the last
!    expression of the sequence in GIMPLE form.
! 
!    PRE_P points to the list where the side effects for all the
!        expressions in the sequence will be emitted.
! 
!    WANT_VALUE is true when the result of the last COMPOUND_EXPR is used.  */
! /* ??? Should rearrange to share the pre-queue with all the indirect
!    invocations of gimplify_main.  Would probably save on creations
!    of statement_list nodes.  */
! 
! static enum gimplify_status
! gimplify_compound_expr (tree *expr_p, tree *pre_p,
! 			tree *post_p ATTRIBUTE_UNUSED,
! 			bool want_value)
! {
!   tree t = *expr_p;
!   enum gimplify_status ret;
! 
!   do
!     {
!       tree sub = TREE_OPERAND (t, 0);
! 
!       if (TREE_CODE (sub) == COMPOUND_EXPR)
! 	{
! 	  ret = gimplify_compound_expr (&sub, pre_p, NULL, false);
! 	  gcc_assert (ret != GS_OK);
! 	}
!       else
! 	gimplify_to_void (sub, pre_p);
! 
!       t = TREE_OPERAND (t, 1);
!     }
!   while (TREE_CODE (t) == COMPOUND_EXPR);
! 
!   if (want_value)
!     {
!       *expr_p = t;
!       return GS_OK;
!     }
! 
!   *expr_p = NULL_TREE;
!   return gimplify_to_void (t, pre_p);
! }
! 
! /* Gimplifies a statement list.  These may be created either by an
!    enlightened front-end, or by shortcut_cond_expr.  */
! 
! static enum gimplify_status
! gimplify_statement_list (tree *expr_p, tree *pre_p,
! 			 tree *post_p ATTRIBUTE_UNUSED,
! 			 bool want_value)
! {
!   tree_stmt_iterator i = tsi_start (*expr_p);
! 
!   if (tsi_end_p (i))
!     return GS_ALL_DONE;
! 
!   for (; !tsi_one_before_end_p (i); tsi_next (&i))
!     gimplify_to_void (tsi_stmt (i), pre_p);
! 
!   if (want_value)
!     {
!       *expr_p = tsi_stmt (i);
!       return GS_OK;
!     }
! 
!   *expr_p = NULL_TREE;
!   return gimplify_to_void (tsi_stmt (i), pre_p);
! }
! 
! 
! /* Gimplify with_size expression *EXPR_P, appending new statements to PRE_P
!    and POST_P queues.  If WANT_VALUE is true, value of the expression is
!    needed.  */
! 
! static enum gimplify_status
! gimplify_with_size_expr (tree *expr_p, tree *pre_p, tree *post_p,
! 			 bool want_value)
! {
!   if (want_value)
!     {
!       if (TREE_CODE (*expr_p) == CALL_EXPR)
! 	gimplify_to_rhs (TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			 &TREE_OPERAND (*expr_p, 0));
!       else
! 	gimplify_to_addressable (TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 				 &TREE_OPERAND (*expr_p, 0));
! 
!       gimplify_to_operand (TREE_OPERAND (*expr_p, 1), pre_p, post_p,
! 			   &TREE_OPERAND (*expr_p, 1), false);
!     }
!   else
!     {
!       gimplify_to_void (TREE_OPERAND (*expr_p, 0), pre_p);
!       gimplify_to_void (TREE_OPERAND (*expr_p, 1), pre_p);
!       *expr_p = NULL;
!     }
! 
!   return GS_ALL_DONE;
! }
! 
! /*  Gimplify a SAVE_EXPR node.  EXPR_P points to the expression to
!     gimplify.  After gimplification, EXPR_P will point to a new temporary
!     that holds the original value of the SAVE_EXPR node.
! 
!     PRE_P points to the list where side effects that must happen before
! 	*EXPR_P should be stored.
! 
!     WANT_VALUE is true if the value of *EXPR_P is needed.  */
! 
! static enum gimplify_status
! gimplify_save_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
! {
!   enum gimplify_status ret = GS_ALL_DONE;
!   tree val;
! 
!   gcc_assert (TREE_CODE (*expr_p) == SAVE_EXPR);
!   val = TREE_OPERAND (*expr_p, 0);
! 
!   /* If the SAVE_EXPR has not been resolved, then evaluate it once.  */
!   if (!SAVE_EXPR_RESOLVED_P (*expr_p))
!     {
!       /* The operand may be a void-valued expression such as SAVE_EXPRs
! 	 generated by the Java frontend for class initialization.  It is
! 	 being executed only for its side-effects.  */
!       if (TREE_TYPE (val) == void_type_node)
! 	{
! 	  ret = gimplify_to_void (TREE_OPERAND (*expr_p, 0), pre_p);
! 	  val = NULL;
! 	}
!       else
! 	val = get_initialized_tmp_var (val, pre_p, post_p);
! 
!       TREE_OPERAND (*expr_p, 0) = val;
!       SAVE_EXPR_RESOLVED_P (*expr_p) = 1;
!     }
! 
!   *expr_p = (want_value ? val : NULL_TREE);
!   return ret;
! }
! 
! /*  Re-write the ADDR_EXPR node pointed by EXPR_P
! 
!       unary_expr
! 	      : ...
! 	      | '&' varname
! 	      ...
! 
!     PRE_P points to the list where side effects that must happen before
! 	*EXPR_P should be stored.
! 
!     POST_P points to the list where side effects that must happen after
! 	*EXPR_P should be stored.
! 
!     WANT_VALUE is true if the value of the expression is needed.  */
! 
! static enum gimplify_status
! gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
! {
!   tree expr = *expr_p;
!   tree op0 = TREE_OPERAND (expr, 0);
!   enum gimplify_status ret;
! 
!   switch (TREE_CODE (op0))
      {
      case INDIRECT_REF:
      case MISALIGNED_INDIRECT_REF:
*************** gimplify_addr_expr (tree *expr_p, tree *
*** 3448,3459 ****
        break;
  
      default:
!       /* We use fb_either here because the C frontend sometimes takes
! 	 the address of a call that returns a struct; see
! 	 gcc.dg/c99-array-lval-1.c.  The gimplifier will correctly make
! 	 the implied temporary explicit.  */
!       ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, post_p,
! 			   is_gimple_addressable, fb_either);
        if (ret != GS_ERROR)
  	{
  	  op0 = TREE_OPERAND (expr, 0);
--- 3853,3860 ----
        break;
  
      default:
!       ret = gimplify_to_addressable (TREE_OPERAND (expr, 0), pre_p, post_p,
! 				     &TREE_OPERAND (expr, 0));
        if (ret != GS_ERROR)
  	{
  	  op0 = TREE_OPERAND (expr, 0);
*************** gimplify_addr_expr (tree *expr_p, tree *
*** 3470,3475 ****
--- 3871,3879 ----
  	  /* Mark the RHS addressable.  */
  	  lang_hooks.mark_addressable (TREE_OPERAND (expr, 0));
  	}
+ 
+       if (!want_value)
+ 	*expr_p = NULL_TREE;
        break;
      }
  
*************** gimplify_asm_expr (tree *expr_p, tree *p
*** 3508,3516 ****
        if (!allows_reg && allows_mem)
  	lang_hooks.mark_addressable (TREE_VALUE (link));
  
!       tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
! 			    is_inout ? is_gimple_min_lval : is_gimple_lvalue,
! 			    fb_lvalue | fb_mayfail);
        if (tret == GS_ERROR)
  	{
  	  error ("invalid lvalue in asm output %d", i);
--- 3912,3923 ----
        if (!allows_reg && allows_mem)
  	lang_hooks.mark_addressable (TREE_VALUE (link));
  
!       if (is_inout)
! 	tret = gimplify_to_min_lval (TREE_VALUE (link), pre_p, post_p,
! 				     &TREE_VALUE (link));
!       else
! 	tret = gimplify_to_lhs (TREE_VALUE (link), pre_p, post_p,
! 				&TREE_VALUE (link));
        if (tret == GS_ERROR)
  	{
  	  error ("invalid lvalue in asm output %d", i);
*************** gimplify_asm_expr (tree *expr_p, tree *p
*** 3621,3628 ****
        if (!allows_reg && allows_mem)
  	{
  	  lang_hooks.mark_addressable (TREE_VALUE (link));
! 	  tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
! 				is_gimple_lvalue, fb_lvalue | fb_mayfail);
  	  if (tret == GS_ERROR)
  	    {
  	      error ("memory input %d is not directly addressable", i);
--- 4028,4035 ----
        if (!allows_reg && allows_mem)
  	{
  	  lang_hooks.mark_addressable (TREE_VALUE (link));
! 	  tret = gimplify_to_lhs (TREE_VALUE (link), pre_p, post_p,
! 				  &TREE_VALUE (link));
  	  if (tret == GS_ERROR)
  	    {
  	      error ("memory input %d is not directly addressable", i);
*************** gimplify_asm_expr (tree *expr_p, tree *p
*** 3631,3643 ****
  	}
        else
  	{
! 	  tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
! 				is_gimple_asm_val, fb_rvalue);
  	  if (tret == GS_ERROR)
  	    ret = tret;
  	}
      }
  
    return ret;
  }
  
--- 4038,4052 ----
  	}
        else
  	{
! 	  tret = gimplify_to_asm_val (TREE_VALUE (link), pre_p, post_p,
! 				      &TREE_VALUE (link));
  	  if (tret == GS_ERROR)
  	    ret = tret;
  	}
      }
  
+   add_statement (*expr_p, pre_p);
+   *expr_p = NULL_TREE;
    return ret;
  }
  
*************** gimplify_cleanup_point_expr (tree *expr_
*** 3698,3705 ****
  
  	      sl = tsi_split_statement_list_after (&iter);
  	      tfe = build (code, void_type_node, sl, NULL_TREE);
! 	      append_to_statement_list (TREE_OPERAND (wce, 0),
! 				        &TREE_OPERAND (tfe, 1));
  	      *wce_p = tfe;
  	      iter = tsi_start (sl);
  	    }
--- 4107,4114 ----
  
  	      sl = tsi_split_statement_list_after (&iter);
  	      tfe = build (code, void_type_node, sl, NULL_TREE);
! 	      add_statement (TREE_OPERAND (wce, 0),
! 			     &TREE_OPERAND (tfe, 1));
  	      *wce_p = tfe;
  	      iter = tsi_start (sl);
  	    }
*************** gimplify_cleanup_point_expr (tree *expr_
*** 3708,3724 ****
  	tsi_next (&iter);
      }
  
!   if (temp)
!     {
!       *expr_p = temp;
!       append_to_statement_list (body, pre_p);
!       return GS_OK;
!     }
!   else
!     {
!       *expr_p = body;
!       return GS_ALL_DONE;
!     }
  }
  
  /* Insert a cleanup marker for gimplify_cleanup_point_expr.  CLEANUP
--- 4117,4125 ----
  	tsi_next (&iter);
      }
  
!   add_statement (body, pre_p);
!   *expr_p = temp;
!   return GS_OK;
  }
  
  /* Insert a cleanup marker for gimplify_cleanup_point_expr.  CLEANUP
*************** gimple_push_cleanup (tree var, tree clea
*** 3764,3772 ****
  			  boolean_true_node);
        cleanup = build (COND_EXPR, void_type_node, flag, cleanup, NULL);
        wce = build (WITH_CLEANUP_EXPR, void_type_node, cleanup);
!       append_to_statement_list (ffalse, &gimplify_ctxp->conditional_cleanups);
!       append_to_statement_list (wce, &gimplify_ctxp->conditional_cleanups);
!       append_to_statement_list (ftrue, pre_p);
  
        /* Because of this manipulation, and the EH edges that jump
  	 threading cannot redirect, the temporary (VAR) will appear
--- 4165,4173 ----
  			  boolean_true_node);
        cleanup = build (COND_EXPR, void_type_node, flag, cleanup, NULL);
        wce = build (WITH_CLEANUP_EXPR, void_type_node, cleanup);
!       add_statement (ffalse, &gimplify_ctxp->conditional_cleanups);
!       add_statement (wce, &gimplify_ctxp->conditional_cleanups);
!       add_statement (ftrue, pre_p);
  
        /* Because of this manipulation, and the EH edges that jump
  	 threading cannot redirect, the temporary (VAR) will appear
*************** gimple_push_cleanup (tree var, tree clea
*** 3777,3783 ****
      {
        wce = build (WITH_CLEANUP_EXPR, void_type_node, cleanup);
        CLEANUP_EH_ONLY (wce) = eh_only;
!       append_to_statement_list (wce, pre_p);
      }
  
    gimplify_stmt (&TREE_OPERAND (wce, 0));
--- 4178,4184 ----
      {
        wce = build (WITH_CLEANUP_EXPR, void_type_node, cleanup);
        CLEANUP_EH_ONLY (wce) = eh_only;
!       add_statement (wce, pre_p);
      }
  
    gimplify_stmt (&TREE_OPERAND (wce, 0));
*************** gimple_push_cleanup (tree var, tree clea
*** 3786,3792 ****
  /* Gimplify a TARGET_EXPR which doesn't appear on the rhs of an INIT_EXPR.  */
  
  static enum gimplify_status
! gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
  {
    tree targ = *expr_p;
    tree temp = TARGET_EXPR_SLOT (targ);
--- 4187,4195 ----
  /* Gimplify a TARGET_EXPR which doesn't appear on the rhs of an INIT_EXPR.  */
  
  static enum gimplify_status
! gimplify_target_expr (tree *expr_p, tree *pre_p,
! 		      tree *post_p ATTRIBUTE_UNUSED,
! 		      bool want_value ATTRIBUTE_UNUSED)
  {
    tree targ = *expr_p;
    tree temp = TARGET_EXPR_SLOT (targ);
*************** gimplify_target_expr (tree *expr_p, tree
*** 3802,3824 ****
        /* If TARGET_EXPR_INITIAL is void, then the mere evaluation of the
  	 expression is supposed to initialize the slot.  */
        if (VOID_TYPE_P (TREE_TYPE (init)))
! 	ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none);
        else
  	{
            /* Special handling for BIND_EXPR can result in fewer temps.  */
  	  ret = GS_OK;
            if (TREE_CODE (init) == BIND_EXPR)
! 	    gimplify_bind_expr (&init, temp, pre_p);
  	  if (init != temp)
! 	    {
! 	      init = build (MODIFY_EXPR, void_type_node, temp, init);
! 	      ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt,
! 				   fb_none);
! 	    }
  	}
        if (ret == GS_ERROR)
  	return GS_ERROR;
-       append_to_statement_list (init, pre_p);
  
        /* If needed, push the cleanup for the temp.  */
        if (TARGET_EXPR_CLEANUP (targ))
--- 4205,4223 ----
        /* If TARGET_EXPR_INITIAL is void, then the mere evaluation of the
  	 expression is supposed to initialize the slot.  */
        if (VOID_TYPE_P (TREE_TYPE (init)))
! 	ret = gimplify_to_void (init, pre_p);
        else
  	{
            /* Special handling for BIND_EXPR can result in fewer temps.  */
  	  ret = GS_OK;
            if (TREE_CODE (init) == BIND_EXPR)
! 	    gimplify_bind_expr (&init, temp, pre_p, true);
  	  if (init != temp)
! 	    init = build2 (MODIFY_EXPR, void_type_node, temp, init);
! 	  ret = gimplify_to_void (init, pre_p);
  	}
        if (ret == GS_ERROR)
  	return GS_ERROR;
  
        /* If needed, push the cleanup for the temp.  */
        if (TARGET_EXPR_CLEANUP (targ))
*************** gimplify_target_expr (tree *expr_p, tree
*** 3848,3854 ****
  void
  gimplify_stmt (tree *stmt_p)
  {
!   gimplify_expr (stmt_p, NULL, NULL, is_gimple_stmt, fb_none);
  }
  
  /* Similarly, but force the result to be a STATEMENT_LIST.  */
--- 4247,4255 ----
  void
  gimplify_stmt (tree *stmt_p)
  {
!   tree stmts = NULL_TREE;
!   gimplify_to_void (*stmt_p, &stmts);
!   *stmt_p = stmts;
  }
  
  /* Similarly, but force the result to be a STATEMENT_LIST.  */
*************** gimplify_to_stmt_list (tree *stmt_p)
*** 3868,3875 ****
  }
  
  
! /*  Gimplifies the expression tree pointed by EXPR_P.  Return 0 if
!     gimplification failed.
  
      PRE_P points to the list where side effects that must happen before
  	EXPR should be stored.
--- 4269,4279 ----
  }
  
  
! /* Gimplifies the expression tree EXPR.  If RHS is NULL, just the side effects
!    of EXPR are gimplified and stored to the PRE_P list.  If RHS is not NULL,
!    EXPR is gimplified to rhs and stored to *RHS.  Additionally, if EXPR is an
!    lvalue, and MUST_PRESERVE_LVALUE is set in flags, *RHS is guaranteed to be an
!    lvalue as well.
  
      PRE_P points to the list where side effects that must happen before
  	EXPR should be stored.
*************** gimplify_to_stmt_list (tree *stmt_p)
*** 3879,3933 ****
  	that case, we copy the result to a temporary, emit the
  	post-effects, and then return the temporary.
  
-     GIMPLE_TEST_F points to a function that takes a tree T and
- 	returns nonzero if T is in the GIMPLE form requested by the
- 	caller.  The GIMPLE predicates are in tree-gimple.c.
- 
- 	This test is used twice.  Before gimplification, the test is
- 	invoked to determine whether *EXPR_P is already gimple enough.  If
- 	that fails, *EXPR_P is gimplified according to its code and
- 	GIMPLE_TEST_F is called again.  If the test still fails, then a new
- 	temporary variable is created and assigned the value of the
- 	gimplified expression.
- 
-     FALLBACK tells the function what sort of a temporary we want.  If the 1
- 	bit is set, an rvalue is OK.  If the 2 bit is set, an lvalue is OK.
- 	If both are set, either is OK, but an lvalue is preferable.
- 
      The return value is either GS_ERROR or GS_ALL_DONE, since this function
      iterates until solution.  */
  
! enum gimplify_status
! gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
! 	       bool (* gimple_test_f) (tree), fallback_t fallback)
  {
    tree tmp;
-   tree internal_pre = NULL_TREE;
    tree internal_post = NULL_TREE;
    tree save_expr;
-   int is_statement = (pre_p == NULL);
    location_t saved_location;
    enum gimplify_status ret;
  
!   save_expr = *expr_p;
!   if (save_expr == NULL_TREE)
!     return GS_ALL_DONE;
  
!   /* We used to check the predicate here and return immediately if it
!      succeeds.  This is wrong; the design is for gimplification to be
!      idempotent, and for the predicates to only test for valid forms, not
!      whether they are fully simplified.  */
  
    /* Set up our internal queues if needed.  */
-   if (pre_p == NULL)
-     pre_p = &internal_pre;
    if (post_p == NULL)
      post_p = &internal_post;
  
    saved_location = input_location;
!   if (save_expr != error_mark_node
!       && EXPR_HAS_LOCATION (*expr_p))
!     input_location = EXPR_LOCATION (*expr_p);
  
    /* Loop over the specific gimplifiers until the toplevel node
       remains the same.  */
--- 4283,4321 ----
  	that case, we copy the result to a temporary, emit the
  	post-effects, and then return the temporary.
  
      The return value is either GS_ERROR or GS_ALL_DONE, since this function
      iterates until solution.  */
  
! static enum gimplify_status
! gimplify_main (tree expr, tree *pre_p, tree *post_p, tree *rhs, unsigned flags)
  {
    tree tmp;
    tree internal_post = NULL_TREE;
    tree save_expr;
    location_t saved_location;
    enum gimplify_status ret;
+   bool want_value = (rhs != NULL);
  
!   if (!expr)
!     {
!       if (rhs)
! 	*rhs = NULL;
!       return GS_ALL_DONE;
!     }
  
!   /* If we do not want a value and the expression does not have side effects,
!      we are done.  */
!   if (!want_value && !TREE_SIDE_EFFECTS (expr))
!     return GS_ALL_DONE;
  
    /* Set up our internal queues if needed.  */
    if (post_p == NULL)
      post_p = &internal_post;
  
    saved_location = input_location;
!   if (expr != error_mark_node
!       && EXPR_HAS_LOCATION (expr))
!     input_location = EXPR_LOCATION (expr);
  
    /* Loop over the specific gimplifiers until the toplevel node
       remains the same.  */
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 3935,3968 ****
      {
        /* Strip away as many useless type conversions as possible
  	 at the toplevel.  */
!       STRIP_USELESS_TYPE_CONVERSION (*expr_p);
! 
!       /* Remember the expr.  */
!       save_expr = *expr_p;
  
        /* Die, die, die, my darling.  */
!       if (save_expr == error_mark_node
! 	  || (TREE_TYPE (save_expr)
! 	      && TREE_TYPE (save_expr) == error_mark_node))
  	{
  	  ret = GS_ERROR;
  	  break;
  	}
  
        /* Do any language-specific gimplification.  */
!       ret = lang_hooks.gimplify_expr (expr_p, pre_p, post_p);
        if (ret == GS_OK)
  	{
! 	  if (*expr_p == NULL_TREE)
  	    break;
! 	  if (*expr_p != save_expr)
  	    continue;
  	}
        else if (ret != GS_UNHANDLED)
  	break;
  
        ret = GS_OK;
!       switch (TREE_CODE (*expr_p))
  	{
  	  /* First deal with the special cases.  */
  
--- 4323,4365 ----
      {
        /* Strip away as many useless type conversions as possible
  	 at the toplevel.  */
!       STRIP_USELESS_TYPE_CONVERSION (expr);
  
        /* Die, die, die, my darling.  */
!       if (expr == error_mark_node
! 	  || TREE_TYPE (expr) == error_mark_node)
  	{
  	  ret = GS_ERROR;
  	  break;
  	}
  
+       /* Check again the side effects, since we might have simplified the
+ 	 expression.  */
+ 	 
+       if (!want_value && !TREE_SIDE_EFFECTS (expr))
+ 	{
+ 	  expr = NULL_TREE;
+ 	  ret = GS_ALL_DONE;
+ 	  break;
+ 	}
+ 
+       /* Remember the expr.  */
+       save_expr = expr;
+ 
        /* Do any language-specific gimplification.  */
!       ret = lang_hooks.gimplify_expr (&expr, pre_p, post_p);
        if (ret == GS_OK)
  	{
! 	  if (expr == NULL_TREE)
  	    break;
! 	  if (expr != save_expr)
  	    continue;
  	}
        else if (ret != GS_UNHANDLED)
  	break;
  
        ret = GS_OK;
!       switch (TREE_CODE (expr))
  	{
  	  /* First deal with the special cases.  */
  
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 3970,3977 ****
  	case POSTDECREMENT_EXPR:
  	case PREINCREMENT_EXPR:
  	case PREDECREMENT_EXPR:
! 	  ret = gimplify_self_mod_expr (expr_p, pre_p, post_p,
! 					fallback != fb_none);
  	  break;
  
  	case ARRAY_REF:
--- 4367,4373 ----
  	case POSTDECREMENT_EXPR:
  	case PREINCREMENT_EXPR:
  	case PREDECREMENT_EXPR:
! 	  ret = gimplify_self_mod_expr (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case ARRAY_REF:
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 3980,4094 ****
  	case IMAGPART_EXPR:
  	case COMPONENT_REF:
  	case VIEW_CONVERT_EXPR:
! 	  ret = gimplify_compound_lval (expr_p, pre_p, post_p,
! 					fallback ? fallback : fb_rvalue);
  	  break;
  
  	case COND_EXPR:
! 	  ret = gimplify_cond_expr (expr_p, pre_p, post_p, NULL_TREE,
! 				    fallback);
! 	  /* C99 code may assign to an array in a structure value of a
! 	     conditional expression, and this has undefined behavior
! 	     only on execution, so create a temporary if an lvalue is
! 	     required.  */
! 	  if (fallback == fb_lvalue)
! 	    {
! 	      *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
! 	      lang_hooks.mark_addressable (*expr_p);
! 	    }
  	  break;
  
  	case CALL_EXPR:
! 	  ret = gimplify_call_expr (expr_p, pre_p, fallback != fb_none);
! 	  /* C99 code may assign to an array in a structure returned
! 	     from a function, and this has undefined behavior only on
! 	     execution, so create a temporary if an lvalue is
! 	     required.  */
! 	  if (fallback == fb_lvalue)
! 	    {
! 	      *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
! 	      lang_hooks.mark_addressable (*expr_p);
! 	    }
  	  break;
  
  	case TREE_LIST:
  	  gcc_unreachable ();
  
  	case COMPOUND_EXPR:
! 	  ret = gimplify_compound_expr (expr_p, pre_p, fallback != fb_none);
  	  break;
  
  	case MODIFY_EXPR:
  	case INIT_EXPR:
! 	  ret = gimplify_modify_expr (expr_p, pre_p, post_p,
! 				      fallback != fb_none);
  	  break;
  
  	case TRUTH_ANDIF_EXPR:
  	case TRUTH_ORIF_EXPR:
! 	  ret = gimplify_boolean_expr (expr_p);
  	  break;
  
  	case TRUTH_NOT_EXPR:
! 	  TREE_OPERAND (*expr_p, 0)
! 	    = gimple_boolify (TREE_OPERAND (*expr_p, 0));
! 	  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			       is_gimple_val, fb_rvalue);
! 	  recalculate_side_effects (*expr_p);
  	  break;
  
  	case ADDR_EXPR:
! 	  ret = gimplify_addr_expr (expr_p, pre_p, post_p);
  	  break;
  
  	case VA_ARG_EXPR:
! 	  ret = gimplify_va_arg_expr (expr_p, pre_p, post_p);
  	  break;
  
  	case CONVERT_EXPR:
  	case NOP_EXPR:
! 	  if (IS_EMPTY_STMT (*expr_p))
! 	    {
! 	      ret = GS_ALL_DONE;
! 	      break;
! 	    }
! 
! 	  if (VOID_TYPE_P (TREE_TYPE (*expr_p))
! 	      || fallback == fb_none)
! 	    {
! 	      /* Just strip a conversion to void (or in void context) and
! 		 try again.  */
! 	      *expr_p = TREE_OPERAND (*expr_p, 0);
! 	      break;
! 	    }
! 
! 	  ret = gimplify_conversion (expr_p);
! 	  if (ret == GS_ERROR)
! 	    break;
! 	  if (*expr_p != save_expr)
! 	    break;
! 	  /* FALLTHRU */
! 
! 	case FIX_TRUNC_EXPR:
! 	case FIX_CEIL_EXPR:
! 	case FIX_FLOOR_EXPR:
! 	case FIX_ROUND_EXPR:
! 	  /* unary_expr: ... | '(' cast ')' val | ...  */
! 	  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			       is_gimple_val, fb_rvalue);
! 	  recalculate_side_effects (*expr_p);
  	  break;
  
  	case INDIRECT_REF:
! 	  *expr_p = fold_indirect_ref (*expr_p);
! 	  if (*expr_p != save_expr)
  	    break;
  	  /* else fall through.  */
  	case ALIGN_INDIRECT_REF:
  	case MISALIGNED_INDIRECT_REF:
! 	  ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			       is_gimple_reg, fb_rvalue);
! 	  recalculate_side_effects (*expr_p);
  	  break;
  
  	  /* Constants need not be gimplified.  */
--- 4376,4439 ----
  	case IMAGPART_EXPR:
  	case COMPONENT_REF:
  	case VIEW_CONVERT_EXPR:
! 	case BIT_FIELD_REF:
! 	  ret = gimplify_compound_lval (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case COND_EXPR:
! 	  ret = gimplify_cond_expr (&expr, pre_p, post_p, NULL_TREE,
! 				    want_value, flags & MUST_PRESERVE_LVALUE);
  	  break;
  
  	case CALL_EXPR:
! 	  ret = gimplify_call_expr (&expr, pre_p, want_value);
  	  break;
  
  	case TREE_LIST:
  	  gcc_unreachable ();
  
  	case COMPOUND_EXPR:
! 	  ret = gimplify_compound_expr (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case MODIFY_EXPR:
  	case INIT_EXPR:
! 	  ret = gimplify_modify_expr (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case TRUTH_ANDIF_EXPR:
  	case TRUTH_ORIF_EXPR:
! 	  ret = gimplify_boolean_expr (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case TRUTH_NOT_EXPR:
! 	  TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
! 	  ret = gimplify_unary_expr (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case ADDR_EXPR:
! 	  ret = gimplify_addr_expr (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case VA_ARG_EXPR:
! 	  ret = gimplify_va_arg_expr (&expr, pre_p, post_p);
! 	  if (!want_value)
! 	    expr = NULL_TREE;
  	  break;
  
  	case CONVERT_EXPR:
  	case NOP_EXPR:
! 	  ret = gimplify_conversion (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case INDIRECT_REF:
! 	  expr = fold_indirect_ref (expr);
! 	  if (expr != save_expr)
  	    break;
  	  /* else fall through.  */
  	case ALIGN_INDIRECT_REF:
  	case MISALIGNED_INDIRECT_REF:
! 	  ret = gimplify_indirect_ref (&expr, pre_p, post_p, want_value);
  	  break;
  
  	  /* Constants need not be gimplified.  */
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 4101,4118 ****
  	  break;
  
  	case CONST_DECL:
! 	  /* If we require an lvalue, such as for ADDR_EXPR, retain the
! 	     CONST_DECL node.  Otherwise the decl is replaceable by its
! 	     value.  */
! 	  /* ??? Should be == fb_lvalue, but ADDR_EXPR passes fb_either.  */
! 	  if (fallback & fb_lvalue)
! 	    ret = GS_ALL_DONE;
! 	  else
! 	    *expr_p = DECL_INITIAL (*expr_p);
  	  break;
  
  	case DECL_EXPR:
! 	  ret = gimplify_decl_expr (expr_p);
  	  break;
  
  	case EXC_PTR_EXPR:
--- 4446,4458 ----
  	  break;
  
  	case CONST_DECL:
! 	  ret = gimplify_const_decl (&expr, pre_p, post_p, want_value,
! 				     flags & MUST_PRESERVE_LVALUE);
  	  break;
  
  	case DECL_EXPR:
! 	  gcc_assert (!want_value);
! 	  ret = gimplify_decl_expr (&expr, pre_p, post_p);
  	  break;
  
  	case EXC_PTR_EXPR:
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 4121,4208 ****
  	  break;
  
  	case BIND_EXPR:
! 	  ret = gimplify_bind_expr (expr_p, NULL, pre_p);
  	  break;
  
  	case LOOP_EXPR:
! 	  ret = gimplify_loop_expr (expr_p, pre_p);
  	  break;
  
  	case SWITCH_EXPR:
! 	  ret = gimplify_switch_expr (expr_p, pre_p);
  	  break;
  
  	case EXIT_EXPR:
! 	  ret = gimplify_exit_expr (expr_p);
  	  break;
  
  	case GOTO_EXPR:
! 	  /* If the target is not LABEL, then it is a computed jump
! 	     and the target needs to be gimplified.  */
! 	  if (TREE_CODE (GOTO_DESTINATION (*expr_p)) != LABEL_DECL)
! 	    ret = gimplify_expr (&GOTO_DESTINATION (*expr_p), pre_p,
! 				 NULL, is_gimple_val, fb_rvalue);
  	  break;
  
  	case LABEL_EXPR:
! 	  ret = GS_ALL_DONE;
! 	  gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p))
! 		      == current_function_decl);
  	  break;
  
  	case CASE_LABEL_EXPR:
! 	  ret = gimplify_case_label_expr (expr_p);
  	  break;
  
  	case RETURN_EXPR:
! 	  ret = gimplify_return_expr (*expr_p, pre_p);
  	  break;
  
  	case CONSTRUCTOR:
! 	  /* Don't reduce this in place; let gimplify_init_constructor work its
! 	     magic.  Buf if we're just elaborating this for side effects, just
! 	     gimplify any element that has side-effects.  */
! 	  if (fallback == fb_none)
! 	    {
! 	      unsigned HOST_WIDE_INT ix;
! 	      constructor_elt *ce;
! 	      for (ix = 0;
! 		   VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (*expr_p),
! 				ix, ce);
! 		   ix++)
! 		if (TREE_SIDE_EFFECTS (ce->value))
! 		  gimplify_expr (&ce->value, pre_p, post_p,
! 				 gimple_test_f, fallback);
! 
! 	      *expr_p = NULL_TREE;
! 	    }
! 
! 	  ret = GS_ALL_DONE;
  	  break;
  
- 	  /* The following are special cases that are not handled by the
- 	     original GIMPLE grammar.  */
- 
- 	  /* SAVE_EXPR nodes are converted into a GIMPLE identifier and
- 	     eliminated.  */
  	case SAVE_EXPR:
! 	  ret = gimplify_save_expr (expr_p, pre_p, post_p);
! 	  break;
! 
! 	case BIT_FIELD_REF:
! 	  {
! 	    enum gimplify_status r0, r1, r2;
! 
! 	    r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 				is_gimple_lvalue, fb_either);
! 	    r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
! 				is_gimple_val, fb_rvalue);
! 	    r2 = gimplify_expr (&TREE_OPERAND (*expr_p, 2), pre_p, post_p,
! 				is_gimple_val, fb_rvalue);
! 	    recalculate_side_effects (*expr_p);
! 
! 	    ret = MIN (r0, MIN (r1, r2));
! 	  }
  	  break;
  
  	case NON_LVALUE_EXPR:
--- 4461,4510 ----
  	  break;
  
  	case BIND_EXPR:
! 	  ret = gimplify_bind_expr (&expr, NULL, pre_p, want_value);
  	  break;
  
  	case LOOP_EXPR:
! 	  gcc_assert (!want_value);
! 	  ret = gimplify_loop_expr (&expr, pre_p);
  	  break;
  
  	case SWITCH_EXPR:
! 	  gcc_assert (!want_value);
! 	  ret = gimplify_switch_expr (&expr, pre_p);
  	  break;
  
  	case EXIT_EXPR:
! 	  gcc_assert (!want_value);
! 	  ret = gimplify_exit_expr (&expr, pre_p);
  	  break;
  
  	case GOTO_EXPR:
! 	  gcc_assert (!want_value);
! 	  ret = gimplify_goto_expr (&expr, pre_p);
  	  break;
  
  	case LABEL_EXPR:
! 	  gcc_assert (!want_value);
! 	  ret = gimplify_label_expr (&expr, pre_p);
  	  break;
  
  	case CASE_LABEL_EXPR:
! 	  gcc_assert (!want_value);
! 	  ret = gimplify_case_label_expr (&expr, pre_p);
  	  break;
  
  	case RETURN_EXPR:
! 	  gcc_assert (!want_value);
! 	  ret = gimplify_return_expr (&expr, pre_p);
  	  break;
  
  	case CONSTRUCTOR:
! 	  ret = gimplify_constructor (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case SAVE_EXPR:
! 	  ret = gimplify_save_expr (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case NON_LVALUE_EXPR:
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 4210,4274 ****
  	  gcc_unreachable ();
  
  	case ASM_EXPR:
! 	  ret = gimplify_asm_expr (expr_p, pre_p, post_p);
  	  break;
  
  	case TRY_FINALLY_EXPR:
  	case TRY_CATCH_EXPR:
! 	  gimplify_to_stmt_list (&TREE_OPERAND (*expr_p, 0));
! 	  gimplify_to_stmt_list (&TREE_OPERAND (*expr_p, 1));
! 	  ret = GS_ALL_DONE;
  	  break;
  
  	case CLEANUP_POINT_EXPR:
! 	  ret = gimplify_cleanup_point_expr (expr_p, pre_p);
  	  break;
  
  	case TARGET_EXPR:
! 	  ret = gimplify_target_expr (expr_p, pre_p, post_p);
  	  break;
  
  	case CATCH_EXPR:
! 	  gimplify_to_stmt_list (&CATCH_BODY (*expr_p));
! 	  ret = GS_ALL_DONE;
  	  break;
  
  	case EH_FILTER_EXPR:
! 	  gimplify_to_stmt_list (&EH_FILTER_FAILURE (*expr_p));
! 	  ret = GS_ALL_DONE;
  	  break;
  
  	case OBJ_TYPE_REF:
! 	  {
! 	    enum gimplify_status r0, r1;
! 	    r0 = gimplify_expr (&OBJ_TYPE_REF_OBJECT (*expr_p), pre_p, post_p,
! 			        is_gimple_val, fb_rvalue);
! 	    r1 = gimplify_expr (&OBJ_TYPE_REF_EXPR (*expr_p), pre_p, post_p,
! 			        is_gimple_val, fb_rvalue);
! 	    ret = MIN (r0, r1);
! 	  }
  	  break;
  
  	case LABEL_DECL:
! 	  /* We get here when taking the address of a label.  We mark
! 	     the label as "forced"; meaning it can never be removed and
! 	     it is a potential target for any computed goto.  */
! 	  FORCED_LABEL (*expr_p) = 1;
  	  ret = GS_ALL_DONE;
  	  break;
  
  	case STATEMENT_LIST:
! 	  ret = gimplify_statement_list (expr_p);
  	  break;
  
  	case WITH_SIZE_EXPR:
! 	  {
! 	    gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
! 			   post_p == &internal_post ? NULL : post_p,
! 			   gimple_test_f, fallback);
! 	    gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
! 			   is_gimple_val, fb_rvalue);
! 	  }
  	  break;
  
  	case VAR_DECL:
--- 4512,4570 ----
  	  gcc_unreachable ();
  
  	case ASM_EXPR:
! 	  gcc_assert (!want_value);
! 	  ret = gimplify_asm_expr (&expr, pre_p, post_p);
  	  break;
  
  	case TRY_FINALLY_EXPR:
+ 	  gcc_assert (!want_value);
+ 	  ret = gimplify_try_finally_expr (&expr, pre_p);
+ 	  break;
+ 
  	case TRY_CATCH_EXPR:
! 	  gcc_assert (!want_value);
! 	  ret = gimplify_try_catch_expr (&expr, pre_p);
  	  break;
  
  	case CLEANUP_POINT_EXPR:
! 	  ret = gimplify_cleanup_point_expr (&expr, pre_p);
  	  break;
  
  	case TARGET_EXPR:
! 	  ret = gimplify_target_expr (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case CATCH_EXPR:
! 	  gcc_assert (!want_value);
! 	  ret = gimplify_catch_expr (&expr, pre_p);
  	  break;
  
  	case EH_FILTER_EXPR:
! 	  gcc_assert (!want_value);
! 	  ret = gimplify_eh_filter_expr (&expr, pre_p);
  	  break;
  
  	case OBJ_TYPE_REF:
! 	  ret = gimplify_obj_type_ref (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case LABEL_DECL:
! 	  if (want_value)
! 	    {
! 	      /* We get here when taking the address of a label.  We mark
! 		 the label as "forced"; meaning it can never be removed and
! 		 it is a potential target for any computed goto.  */
! 	      FORCED_LABEL (expr) = 1;
! 	    }
  	  ret = GS_ALL_DONE;
  	  break;
  
  	case STATEMENT_LIST:
! 	  ret = gimplify_statement_list (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case WITH_SIZE_EXPR:
! 	  ret = gimplify_with_size_expr (&expr, pre_p, post_p, want_value);
  	  break;
  
  	case VAR_DECL:
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 4278,4287 ****
  	     be really nice if the front end wouldn't leak these at all.
  	     Currently the only known culprit is C++ destructors, as seen
  	     in g++.old-deja/g++.jason/binding.C.  */
! 	  tmp = *expr_p;
! 	  if (!TREE_STATIC (tmp) && !DECL_EXTERNAL (tmp)
! 	      && decl_function_context (tmp) == current_function_decl
! 	      && !DECL_SEEN_IN_BIND_EXPR_P (tmp))
  	    {
  	      gcc_assert (errorcount || sorrycount);
  	      ret = GS_ERROR;
--- 4574,4582 ----
  	     be really nice if the front end wouldn't leak these at all.
  	     Currently the only known culprit is C++ destructors, as seen
  	     in g++.old-deja/g++.jason/binding.C.  */
! 	  if (!TREE_STATIC (expr) && !DECL_EXTERNAL (expr)
! 	      && decl_function_context (expr) == current_function_decl
! 	      && !DECL_SEEN_IN_BIND_EXPR_P (expr))
  	    {
  	      gcc_assert (errorcount || sorrycount);
  	      ret = GS_ERROR;
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 4290,4316 ****
  	  /* FALLTHRU */
  
  	case PARM_DECL:
- 	  tmp = *expr_p;
- 
  	  /* If this is a local variable sized decl, it must be accessed
  	     indirectly.  Perform that substitution.  */
! 	  if (DECL_HAS_VALUE_EXPR_P (tmp))
  	    {
! 	      *expr_p = unshare_expr (DECL_VALUE_EXPR (tmp));
  	      ret = GS_OK;
  	      break;
  	    }
  
  	  ret = GS_ALL_DONE;
  	  break;
  
  	case SSA_NAME:
  	  /* Allow callbacks into the gimplifier during optimization.  */
  	  ret = GS_ALL_DONE;
  	  break;
  
  	default:
! 	  switch (TREE_CODE_CLASS (TREE_CODE (*expr_p)))
  	    {
  	    case tcc_comparison:
  	      /* If this is a comparison of objects of aggregate type,
--- 4585,4622 ----
  	  /* FALLTHRU */
  
  	case PARM_DECL:
  	  /* If this is a local variable sized decl, it must be accessed
  	     indirectly.  Perform that substitution.  */
! 	  if (DECL_HAS_VALUE_EXPR_P (expr))
  	    {
! 	      expr = unshare_expr (DECL_VALUE_EXPR (expr));
  	      ret = GS_OK;
  	      break;
  	    }
  
+ 	  if (!want_value)
+ 	    {
+ 	      forget_memory_reference (expr, pre_p);
+ 	      expr = NULL_TREE;
+ 	    }
  	  ret = GS_ALL_DONE;
  	  break;
  
  	case SSA_NAME:
  	  /* Allow callbacks into the gimplifier during optimization.  */
+ 	  if (!want_value)
+ 	    expr = NULL_TREE;
  	  ret = GS_ALL_DONE;
  	  break;
  
+ 	case TRUTH_AND_EXPR:
+ 	case TRUTH_OR_EXPR:
+ 	case TRUTH_XOR_EXPR:
+ 	  ret = gimplify_binary_expr (&expr, pre_p, post_p, want_value);
+ 	  break;
+ 
  	default:
! 	  switch (TREE_CODE_CLASS (TREE_CODE (expr)))
  	    {
  	    case tcc_comparison:
  	      /* If this is a comparison of objects of aggregate type,
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 4319,4379 ****
  	     	 for variable-sized objects, but then we'd have to
  	     	 allow the same nest of reference nodes we allow for
  	     	 MODIFY_EXPR and that's too complex.  */
! 	      if (!AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 1))))
! 		goto expr_2;
! 	      ret = gimplify_variable_sized_compare (expr_p);
  	      break;
  
  	    /* If *EXPR_P does not need to be special-cased, handle it
  	       according to its class.  */
  	    case tcc_unary:
! 	      ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
! 				   post_p, is_gimple_val, fb_rvalue);
  	      break;
  
  	    case tcc_binary:
! 	    expr_2:
! 	      {
! 		enum gimplify_status r0, r1;
! 
! 		r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
! 				    post_p, is_gimple_val, fb_rvalue);
! 		r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p,
! 				    post_p, is_gimple_val, fb_rvalue);
! 
! 		ret = MIN (r0, r1);
! 		break;
! 	      }
  
  	    case tcc_declaration:
  	    case tcc_constant:
  	      ret = GS_ALL_DONE;
! 	      goto dont_recalculate;
  
  	    default:
! 	      gcc_assert (TREE_CODE (*expr_p) == TRUTH_AND_EXPR
! 			  || TREE_CODE (*expr_p) == TRUTH_OR_EXPR
! 			  || TREE_CODE (*expr_p) == TRUTH_XOR_EXPR);
! 	      goto expr_2;
  	    }
- 
- 	  recalculate_side_effects (*expr_p);
- 	dont_recalculate:
  	  break;
  	}
  
!       /* If we replaced *expr_p, gimplify again.  */
!       if (ret == GS_OK && (*expr_p == NULL || *expr_p == save_expr))
  	ret = GS_ALL_DONE;
      }
    while (ret == GS_OK);
  
!   /* If we encountered an error_mark somewhere nested inside, either
!      stub out the statement or propagate the error back out.  */
    if (ret == GS_ERROR)
      {
!       if (is_statement)
! 	*expr_p = NULL;
        goto out;
      }
  
--- 4625,4670 ----
  	     	 for variable-sized objects, but then we'd have to
  	     	 allow the same nest of reference nodes we allow for
  	     	 MODIFY_EXPR and that's too complex.  */
! 	      if (!AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1))))
! 		ret = gimplify_binary_expr (&expr, pre_p, post_p, want_value);
! 	      else
! 		ret = gimplify_variable_sized_compare (&expr, pre_p, post_p,
! 						       want_value);
  	      break;
  
  	    /* If *EXPR_P does not need to be special-cased, handle it
  	       according to its class.  */
  	    case tcc_unary:
! 	      ret = gimplify_unary_expr (&expr, pre_p, post_p, want_value);
  	      break;
  
  	    case tcc_binary:
! 	      ret = gimplify_binary_expr (&expr, pre_p, post_p, want_value);
! 	      break;
  
  	    case tcc_declaration:
  	    case tcc_constant:
  	      ret = GS_ALL_DONE;
! 	      break;
  
  	    default:
! 	      gcc_unreachable ();
  	    }
  	  break;
  	}
  
!       /* If we replaced expr, gimplify again.  */
!       if (ret == GS_OK && (expr == NULL || expr == save_expr))
  	ret = GS_ALL_DONE;
      }
    while (ret == GS_OK);
  
!   /* If we encountered an error_mark somewhere nested inside, propagate the
!      error back out.  */
    if (ret == GS_ERROR)
      {
!       if (rhs)
! 	*rhs = error_mark_node;
        goto out;
      }
  
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 4381,4530 ****
       we handled.  Make sure it doesn't escape from any other context.  */
    gcc_assert (ret != GS_UNHANDLED);
  
!   if (fallback == fb_none && *expr_p && !is_gimple_stmt (*expr_p))
      {
!       /* We aren't looking for a value, and we don't have a valid
! 	 statement.  If it doesn't have side-effects, throw it away.  */
!       if (!TREE_SIDE_EFFECTS (*expr_p))
! 	*expr_p = NULL;
!       else if (!TREE_THIS_VOLATILE (*expr_p))
! 	{
! 	  /* This is probably a _REF that contains something nested that
! 	     has side effects.  Recurse through the operands to find it.  */
! 	  enum tree_code code = TREE_CODE (*expr_p);
! 
! 	  switch (code)
  	    {
! 	    case COMPONENT_REF:
! 	    case REALPART_EXPR: case IMAGPART_EXPR:
! 	      gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			     gimple_test_f, fallback);
! 	      break;
! 
! 	    case ARRAY_REF: case ARRAY_RANGE_REF:
! 	      gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			     gimple_test_f, fallback);
! 	      gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
! 			     gimple_test_f, fallback);
! 	      break;
! 
! 	    default:
! 	       /* Anything else with side-effects must be converted to
! 	       	  a valid statement before we get here.  */
! 	      gcc_unreachable ();
  	    }
! 
! 	  *expr_p = NULL;
! 	}
!       else if (COMPLETE_TYPE_P (TREE_TYPE (*expr_p)))
! 	{
! 	  /* Historically, the compiler has treated a bare
! 	     reference to a volatile lvalue as forcing a load.  */
! 	  tree type = TYPE_MAIN_VARIANT (TREE_TYPE (*expr_p));
! 	  tree tmp = create_tmp_var (type, "vol");
! 	  *expr_p = build (MODIFY_EXPR, type, tmp, *expr_p);
  	}
!       else
! 	/* We can't do anything useful with a volatile reference to
! 	   incomplete type, so just throw it away.  */
! 	*expr_p = NULL;
      }
  
!   /* If we are gimplifying at the statement level, we're done.  Tack
!      everything together and replace the original statement with the
!      gimplified form.  */
!   if (fallback == fb_none || is_statement)
      {
!       if (internal_pre || internal_post)
! 	{
! 	  append_to_statement_list (*expr_p, &internal_pre);
! 	  append_to_statement_list (internal_post, &internal_pre);
! 	  annotate_all_with_locus (&internal_pre, input_location);
! 	  *expr_p = internal_pre;
! 	}
!       else if (!*expr_p)
! 	;
!       else if (TREE_CODE (*expr_p) == STATEMENT_LIST)
! 	annotate_all_with_locus (expr_p, input_location);
!       else
! 	annotate_one_with_locus (*expr_p, input_location);
!       goto out;
      }
  
!   /* Otherwise we're gimplifying a subexpression, so the resulting value is
!      interesting.  */
  
!   /* If it's sufficiently simple already, we're done.  Unless we are
!      handling some post-effects internally; if that's the case, we need to
!      copy into a temp before adding the post-effects to the tree.  */
!   if (!internal_post && (*gimple_test_f) (*expr_p))
!     goto out;
! 
!   /* Otherwise, we need to create a new temporary for the gimplified
!      expression.  */
! 
!   /* We can't return an lvalue if we have an internal postqueue.  The
!      object the lvalue refers to would (probably) be modified by the
!      postqueue; we need to copy the value out first, which means an
!      rvalue.  */
!   if ((fallback & fb_lvalue) && !internal_post
!       && is_gimple_addressable (*expr_p))
!     {
!       /* An lvalue will do.  Take the address of the expression, store it
! 	 in a temporary, and replace the expression with an INDIRECT_REF of
! 	 that temporary.  */
!       tmp = build_fold_addr_expr (*expr_p);
!       gimplify_expr (&tmp, pre_p, post_p, is_gimple_reg, fb_rvalue);
!       *expr_p = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (tmp)), tmp);
!     }
!   else if ((fallback & fb_rvalue) && is_gimple_formal_tmp_rhs (*expr_p))
!     {
!       gcc_assert (!VOID_TYPE_P (TREE_TYPE (*expr_p)));
! 
!       /* An rvalue will do.  Assign the gimplified expression into a new
! 	 temporary TMP and replace the original expression with TMP.  */
! 
!       if (internal_post || (fallback & fb_lvalue))
! 	/* The postqueue might change the value of the expression between
! 	   the initialization and use of the temporary, so we can't use a
! 	   formal temp.  FIXME do we care?  */
! 	*expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
!       else
! 	*expr_p = get_formal_tmp_var (*expr_p, pre_p);
  
!       if (TREE_CODE (*expr_p) != SSA_NAME)
! 	DECL_GIMPLE_FORMAL_TEMP_P (*expr_p) = 1;
!     }
    else
      {
- #ifdef ENABLE_CHECKING
-       if (!(fallback & fb_mayfail))
- 	{
- 	  fprintf (stderr, "gimplification failed:\n");
- 	  print_generic_expr (stderr, *expr_p, 0);
- 	  debug_tree (*expr_p);
- 	  internal_error ("gimplification failed");
- 	}
- #endif
-       gcc_assert (fallback & fb_mayfail);
-       /* If this is an asm statement, and the user asked for the
- 	 impossible, don't die.  Fail and let gimplify_asm_expr
- 	 issue an error.  */
        ret = GS_ERROR;
!       goto out;
      }
  
!   /* Make sure the temporary matches our predicate.  */
!   gcc_assert ((*gimple_test_f) (*expr_p));
  
!   if (internal_post)
      {
!       annotate_all_with_locus (&internal_post, input_location);
!       append_to_statement_list (internal_post, pre_p);
      }
  
!  out:
!   input_location = saved_location;
    return ret;
  }
  
--- 4672,4940 ----
       we handled.  Make sure it doesn't escape from any other context.  */
    gcc_assert (ret != GS_UNHANDLED);
  
!   if (internal_post)
      {
!       if (want_value)
! 	{
! 	  /* We must force the value to temporary, so that the postponed side
! 	     effects can be executed.  */
! 	  if ((flags & MUST_PRESERVE_LVALUE)
! 	      && is_gimple_addressable (expr))
  	    {
! 	      tmp = build_fold_addr_expr (expr);
! 	      tmp = get_initialized_tmp_var (tmp, pre_p, post_p);
! 	      expr =  build1 (INDIRECT_REF, TREE_TYPE (expr), tmp);
  	    }
! 	  else
! 	    expr = get_initialized_tmp_var (expr, pre_p, post_p);
  	}
!       
!       append_to_statement_list (internal_post, pre_p);
      }
  
!   /* Make sure the temporary matches our predicate.  */
!   if (want_value)
      {
!       gcc_assert (is_gimple_formal_tmp_rhs (expr));
!       *rhs = expr;
      }
+   else
+     gcc_assert (!expr);
  
!  out:
!   input_location = saved_location;
!   return ret;
! }
  
! /* Gimplifies EXPR, storing its side effects to PRE_P.  The value
!    of the expression is ignored.  */
  
! enum gimplify_status
! gimplify_to_void (tree expr, tree *pre_p)
! {
!   return gimplify_main (expr, pre_p, NULL, NULL, 0);
! }
! 
! /* Gimplifies EXPR, storing its side effects to PRE_P.  */
! 
! void
! gimplify_and_add (tree expr, tree *pre_p)
! {
!   gimplify_to_void (expr, pre_p);
! }
! 
! /* Forces gimple rhs RHS to operand *OP.  The necessary statements are stored
!    to PRE_P and POST_P.  If CLEAN is true, the result must be a clean temporary
!    not used anywhere else.  */
! 
! enum gimplify_status
! gimplify_rhs_to_operand (tree rhs, tree *pre_p,
! 			 tree *post_p, tree *op,
! 			 bool clean)
! {
!   *op = rhs;
! 
!   if (is_gimple_min_invariant (rhs)
!       /* ADDR_EXPRs must be gimplified, since is_gimple_min_invariant only
! 	 tests TREE_INVARIANT for them.  */
!       && TREE_CODE (rhs) != ADDR_EXPR)
!     return GS_ALL_DONE;
! 
!   if (is_gimple_val (rhs)
!       && (!clean || is_gimple_formal_tmp_var (rhs)))
!     return GS_ALL_DONE;
!     
!   if (clean)
!     *op = get_initialized_tmp_var (rhs, pre_p, post_p);
    else
+     *op = get_formal_tmp_var (rhs, pre_p);
+ 
+   return GS_ALL_DONE;
+ }
+ 
+ /* Gimplifies EXPR to operand *OP.  The necessary statements are stored
+    to PRE_P and POST_P.  If CLEAN is true, the result must be a clean temporary
+    not used anywhere else.  */
+ 
+ enum gimplify_status
+ gimplify_to_operand (tree expr, tree *pre_p, tree *post_p, tree *op,
+ 		     bool clean)
+ {
+   enum gimplify_status ret = gimplify_to_rhs (expr, pre_p, post_p, &expr);
+ 
+   if (ret != GS_ERROR)
+     gimplify_rhs_to_operand (expr, pre_p, post_p, op, clean);
+   return ret;
+ }
+ 
+ /* Gimplifies EXPR to call address *ADDR.  The necessary statements are stored
+    to PRE_P and POST_P.  */
+ 
+ enum gimplify_status
+ gimplify_to_call_addr (tree expr, tree *pre_p, tree *post_p, tree *addr)
+ {
+   enum gimplify_status ret = gimplify_main (expr, pre_p, post_p, &expr, 0);
+ 
+   if (ret == GS_ERROR)
+     {
+       *addr = error_mark_node;
+       return GS_ERROR;
+     }
+ 
+   if (is_gimple_call_addr (expr))
+     {
+       *addr = expr;
+       return ret;
+     }
+ 
+   return gimplify_rhs_to_operand (expr, pre_p, post_p, addr, false);
+ }
+ 
+ /* Gimplifies EXPR to rhs *RHS.  The necessary statements are stored
+    to PRE_P and POST_P.  */
+ 
+ enum gimplify_status
+ gimplify_to_rhs (tree expr, tree *pre_p, tree *post_p, tree *rhs)
+ {
+   return gimplify_main (expr, pre_p, post_p, rhs, 0);
+ }
+ 
+ /* Gimplifies EXPR to rhs *RHS suitable for assignment to LHS.
+    The necessary statements are stored to PRE_P and POST_P.  */
+ 
+ enum gimplify_status
+ gimplify_to_assignment_rhs (tree expr, tree *pre_p, tree *post_p,
+ 			    tree *rhs, tree lhs)
+ {
+   enum gimplify_status ret = gimplify_to_rhs (expr, pre_p, post_p, rhs);
+ 
+   if (ret == GS_ERROR)
+     return GS_ERROR;
+ 
+   if (is_gimple_rhs_for (lhs, *rhs))
+     return ret;
+ 
+   gimplify_rhs_to_operand (*rhs, pre_p, post_p, rhs, false);
+   return ret;
+ }
+ 
+ /* Gimplifies EXPR to addressable ADDR.  The necessary statements are stored to
+    PRE_P and POST_P.  */
+ 
+ enum gimplify_status
+ gimplify_to_addressable (tree expr, tree *pre_p, tree *post_p, tree *addr)
+ {
+   enum gimplify_status ret = gimplify_main (expr, pre_p, post_p, addr,
+ 					    MUST_PRESERVE_LVALUE);
+ 
+   if (ret == GS_ERROR)
+     return GS_ERROR;
+   if (is_gimple_addressable (*addr))
+     return ret;
+ 
+   /* In some rare cases we may happen to get here on correct code.
+      For example,
+ 
+      VIEW_CONVERT_EXPR (a ? b : 4)  -->
+ 
+      if (a)
+        tmp = &b;
+      else
+        tmp = &4; ... oops
+      VIEW_CONVERT_EXPR (*tmp).
+ 
+      So do what is expected in this case and force *addr to
+      temporary.  */
+   *addr = get_initialized_tmp_var (*addr, pre_p, post_p);
+   lang_hooks.mark_addressable (*addr);
+   return ret;
+ }
+ 
+ /* Gimplifies EXPR to lvalue LHS.  The necessary statements are stored to
+    PRE_P and POST_P.  */
+ 
+ enum gimplify_status
+ gimplify_to_lhs (tree expr, tree *pre_p, tree *post_p, tree *lhs)
+ {
+   enum gimplify_status ret = gimplify_main (expr, pre_p, post_p, lhs,
+ 					    MUST_PRESERVE_LVALUE);
+ 
+   if (ret != GS_ERROR
+       && !is_gimple_lvalue (*lhs))
      {
        ret = GS_ERROR;
!       *lhs = error_mark_node;
      }
  
!   return ret;
! }
  
! /* Gimplifies EXPR to min lval LHS.  The necessary statements are stored to
!    PRE_P and POST_P.  */
! 
! enum gimplify_status
! gimplify_to_min_lval (tree expr, tree *pre_p, tree *post_p, tree *lhs)
! {
!   enum gimplify_status ret = gimplify_main (expr, pre_p, post_p, lhs,
! 					    MUST_PRESERVE_LVALUE);
!   tree addr;
! 
!   if (ret == GS_ERROR)
!     return GS_ERROR;
! 
!   if (is_gimple_min_lval (*lhs))
!     return ret;
! 
!   if (is_gimple_addressable (*lhs))
      {
!       addr = build_fold_addr_expr (*lhs);
!       addr = get_formal_tmp_var (addr, pre_p);
!       *lhs = build_fold_indirect_ref (addr);
!     }
!   else
!     {
!       /* This may happen in cases like f().field.  Just force LHS to a
! 	 temporary.  */
!       *lhs = get_initialized_tmp_var (*lhs, pre_p, post_p);
!       lang_hooks.mark_addressable (*lhs);
      }
  
!   return ret;
! }
! 
! /* Gimplifies EXPR to condexpr COND.  The necessary statements are stored to
!    PRE_P and POST_P.  */
! 
! enum gimplify_status
! gimplify_to_condexpr (tree expr, tree *pre_p, tree *post_p, tree *cond)
! {
!   enum gimplify_status ret = gimplify_main (expr, pre_p, post_p, cond, 0);
! 
!   if (ret == GS_ERROR)
!     return GS_ERROR;
! 
!   if (is_gimple_condexpr (*cond))
!     return ret;
! 
!   *cond = get_formal_tmp_var (*cond, pre_p);
!   return ret;
! }
! 
! /* Gimplifies EXPR to asm val VAL.  The necessary statements are stored to
!    PRE_P and POST_P.  */
! 
! enum gimplify_status
! gimplify_to_asm_val (tree expr, tree *pre_p, tree *post_p, tree *val)
! {
!   enum gimplify_status ret = gimplify_main (expr, pre_p, post_p, val, 0);
! 
!   if (ret == GS_ERROR)
!     return GS_ERROR;
! 
!   if (is_gimple_asm_val (*val))
!     return ret;
! 
!   *val = get_formal_tmp_var (*val, pre_p);
    return ret;
  }
  
*************** gimplify_one_sizepos (tree *expr_p, tree
*** 4620,4626 ****
      return;
  
    *expr_p = unshare_expr (*expr_p);
!   gimplify_expr (expr_p, stmt_p, NULL, is_gimple_val, fb_rvalue);
  }
  
  #ifdef ENABLE_CHECKING
--- 5030,5036 ----
      return;
  
    *expr_p = unshare_expr (*expr_p);
!   gimplify_to_operand (*expr_p, stmt_p, NULL, expr_p, true);
  }
  
  #ifdef ENABLE_CHECKING
*************** force_gimple_operand (tree expr, tree *s
*** 4848,4870 ****
  {
    tree t;
    enum gimplify_status ret;
-   gimple_predicate gimple_test_f;
  
    *stmts = NULL_TREE;
  
    if (is_gimple_val (expr))
      return expr;
  
-   gimple_test_f = simple ? is_gimple_val : is_gimple_reg_rhs;
- 
    push_gimplify_context ();
    gimplify_ctxp->into_ssa = in_ssa_p;
  
    if (var)
      expr = build (MODIFY_EXPR, TREE_TYPE (var), var, expr);
  
!   ret = gimplify_expr (&expr, stmts, NULL,
! 		       gimple_test_f, fb_rvalue);
    gcc_assert (ret != GS_ERROR);
  
    if (referenced_vars)
--- 5258,5279 ----
  {
    tree t;
    enum gimplify_status ret;
  
    *stmts = NULL_TREE;
  
    if (is_gimple_val (expr))
      return expr;
  
    push_gimplify_context ();
    gimplify_ctxp->into_ssa = in_ssa_p;
  
    if (var)
      expr = build (MODIFY_EXPR, TREE_TYPE (var), var, expr);
  
!   if (simple)
!     ret = gimplify_to_operand (expr, stmts, NULL, &expr, false);
!   else
!     ret = gimplify_to_rhs (expr, stmts, NULL, &expr);
    gcc_assert (ret != GS_ERROR);
  
    if (referenced_vars)
Index: tree-gimple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-gimple.c,v
retrieving revision 2.41
diff -c -3 -p -r2.41 tree-gimple.c
*** tree-gimple.c	10 Jul 2005 00:27:51 -0000	2.41
--- tree-gimple.c	22 Jul 2005 03:42:34 -0000
*************** is_gimple_mem_rhs (tree t)
*** 123,139 ****
      return is_gimple_formal_tmp_rhs (t);
  }
  
! /* Returns the appropriate RHS predicate for this LHS.  */
  
! gimple_predicate
! rhs_predicate_for (tree lhs)
  {
    if (is_gimple_formal_tmp_var (lhs))
!     return is_gimple_formal_tmp_rhs;
    else if (is_gimple_reg (lhs))
!     return is_gimple_reg_rhs;
    else
!     return is_gimple_mem_rhs;
  }
  
  /*  Return true if T is a valid LHS for a GIMPLE assignment expression.  */
--- 123,139 ----
      return is_gimple_formal_tmp_rhs (t);
  }
  
! /* Returns true if RHS is a good rhs for assignment to LHS.  */
  
! bool
! is_gimple_rhs_for (tree lhs, tree rhs)
  {
    if (is_gimple_formal_tmp_var (lhs))
!     return is_gimple_formal_tmp_rhs (rhs);
    else if (is_gimple_reg (lhs))
!     return is_gimple_reg_rhs (rhs);
    else
!     return is_gimple_mem_rhs (rhs);
  }
  
  /*  Return true if T is a valid LHS for a GIMPLE assignment expression.  */
Index: tree-gimple.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-gimple.h,v
retrieving revision 2.23
diff -c -3 -p -r2.23 tree-gimple.h
*** tree-gimple.h	25 Jun 2005 02:01:22 -0000	2.23
--- tree-gimple.h	22 Jul 2005 03:42:34 -0000
*************** extern void annotate_all_with_locus (tre
*** 38,45 ****
     the basic form of the expression, they don't recurse to make sure that
     underlying nodes are also of the right form.  */
  
- typedef bool (*gimple_predicate)(tree);
- 
  /* Returns true iff T is a valid GIMPLE statement.  */
  extern bool is_gimple_stmt (tree);
  
--- 38,43 ----
*************** extern bool is_gimple_asm_val (tree);
*** 72,80 ****
  extern bool is_gimple_formal_tmp_rhs (tree);
  extern bool is_gimple_reg_rhs (tree);
  extern bool is_gimple_mem_rhs (tree);
! /* Returns the appropriate one of the above three predicates for the LHS
!    T.  */
! extern gimple_predicate rhs_predicate_for (tree);
  
  /* Returns true iff T is a valid if-statement condition.  */
  extern bool is_gimple_condexpr (tree);
--- 70,76 ----
  extern bool is_gimple_formal_tmp_rhs (tree);
  extern bool is_gimple_reg_rhs (tree);
  extern bool is_gimple_mem_rhs (tree);
! bool is_gimple_rhs_for (tree, tree);
  
  /* Returns true iff T is a valid if-statement condition.  */
  extern bool is_gimple_condexpr (tree);
*************** extern tree get_call_expr_in (tree t);
*** 91,105 ****
  
  extern void recalculate_side_effects (tree);
  
- /* FIXME we should deduce this from the predicate.  */
- typedef enum fallback_t {
-   fb_none = 0,
-   fb_rvalue = 1,
-   fb_lvalue = 2,
-   fb_mayfail = 4,
-   fb_either= fb_rvalue | fb_lvalue
- } fallback_t;
- 
  enum gimplify_status {
    GS_ERROR	= -2,	/* Something Bad Seen.  */
    GS_UNHANDLED	= -1,	/* A langhook result for "I dunno".  */
--- 87,92 ----
*************** enum gimplify_status {
*** 107,114 ****
    GS_ALL_DONE	= 1	/* The expression is fully gimplified.  */
  };
  
! extern enum gimplify_status gimplify_expr (tree *, tree *, tree *,
! 					   bool (*) (tree), fallback_t);
  extern void gimplify_type_sizes (tree, tree *);
  extern void gimplify_one_sizepos (tree *, tree *);
  extern void gimplify_stmt (tree *);
--- 94,112 ----
    GS_ALL_DONE	= 1	/* The expression is fully gimplified.  */
  };
  
! enum gimplify_status gimplify_to_void (tree, tree *);
! enum gimplify_status gimplify_rhs_to_operand (tree, tree *, tree *, tree *,
! 					      bool);
! enum gimplify_status gimplify_to_operand (tree, tree *, tree *, tree *, bool);
! enum gimplify_status gimplify_to_call_addr (tree, tree *, tree *, tree *);
! enum gimplify_status gimplify_to_rhs (tree, tree *, tree *, tree *);
! enum gimplify_status gimplify_to_assignment_rhs (tree, tree *, tree *, tree *,
! 						 tree);
! enum gimplify_status gimplify_to_addressable (tree, tree *, tree *, tree *);
! enum gimplify_status gimplify_to_lhs (tree, tree *, tree *, tree *);
! enum gimplify_status gimplify_to_min_lval (tree, tree *, tree *, tree *);
! enum gimplify_status gimplify_to_condexpr (tree, tree *, tree *, tree *);
! enum gimplify_status gimplify_to_asm_val (tree, tree *, tree *, tree *);
  extern void gimplify_type_sizes (tree, tree *);
  extern void gimplify_one_sizepos (tree *, tree *);
  extern void gimplify_stmt (tree *);
Index: config/alpha/alpha.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha.c,v
retrieving revision 1.432
diff -c -3 -p -r1.432 alpha.c
*** config/alpha/alpha.c	12 Jul 2005 03:48:13 -0000	1.432
--- config/alpha/alpha.c	22 Jul 2005 03:42:45 -0000
*************** alpha_va_start (tree valist, rtx nextarg
*** 6173,6179 ****
  static tree
  alpha_gimplify_va_arg_1 (tree type, tree base, tree offset, tree *pre_p)
  {
!   tree type_size, ptr_type, addend, t, addr, internal_post;
  
    /* If the type could not be passed in registers, skip the block
       reserved for the registers.  */
--- 6173,6179 ----
  static tree
  alpha_gimplify_va_arg_1 (tree type, tree base, tree offset, tree *pre_p)
  {
!   tree type_size, ptr_type, addend, t, addr;
  
    /* If the type could not be passed in registers, skip the block
       reserved for the registers.  */
*************** alpha_gimplify_va_arg_1 (tree type, tree
*** 6219,6227 ****
    /* Build the final address and force that value into a temporary.  */
    addr = build (PLUS_EXPR, ptr_type, fold_convert (ptr_type, base),
  	        fold_convert (ptr_type, addend));
!   internal_post = NULL;
!   gimplify_expr (&addr, pre_p, &internal_post, is_gimple_val, fb_rvalue);
!   append_to_statement_list (internal_post, pre_p);
  
    /* Update the offset field.  */
    type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type));
--- 6219,6225 ----
    /* Build the final address and force that value into a temporary.  */
    addr = build (PLUS_EXPR, ptr_type, fold_convert (ptr_type, base),
  	        fold_convert (ptr_type, addend));
!   gimplify_to_operand (addr, pre_p, NULL, &addr, false);
  
    /* Update the offset field.  */
    type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type));
Index: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v
retrieving revision 1.843
diff -c -3 -p -r1.843 i386.c
*** config/i386/i386.c	18 Jul 2005 06:39:18 -0000	1.843
--- config/i386/i386.c	22 Jul 2005 03:42:59 -0000
*************** ix86_gimplify_va_arg (tree valist, tree 
*** 3822,3828 ****
        t = build (BIT_AND_EXPR, TREE_TYPE (t), t,
  		 build_int_cst (TREE_TYPE (t), -align));
      }
!   gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
  
    t2 = build2 (MODIFY_EXPR, void_type_node, addr, t);
    gimplify_and_add (t2, pre_p);
--- 3822,3828 ----
        t = build (BIT_AND_EXPR, TREE_TYPE (t), t,
  		 build_int_cst (TREE_TYPE (t), -align));
      }
!   gimplify_to_operand (t, pre_p, NULL, &t, false);
  
    t2 = build2 (MODIFY_EXPR, void_type_node, addr, t);
    gimplify_and_add (t2, pre_p);
Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.855
diff -c -3 -p -r1.855 rs6000.c
*** config/rs6000/rs6000.c	15 Jul 2005 01:44:35 -0000	1.855
--- config/rs6000/rs6000.c	22 Jul 2005 03:43:15 -0000
*************** rs6000_gimplify_va_arg (tree valist, tre
*** 5661,5667 ****
        t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t,
  		  build_int_cst (NULL_TREE, -align));
      }
!   gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
  
    u = build2 (MODIFY_EXPR, void_type_node, addr, t);
    gimplify_and_add (u, pre_p);
--- 5661,5667 ----
        t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t,
  		  build_int_cst (NULL_TREE, -align));
      }
!   gimplify_to_operand (t, pre_p, NULL, &t, false);
  
    u = build2 (MODIFY_EXPR, void_type_node, addr, t);
    gimplify_and_add (u, pre_p);
Index: config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.244
diff -c -3 -p -r1.244 s390.c
*** config/s390/s390.c	13 Jul 2005 19:34:55 -0000	1.244
--- config/s390/s390.c	22 Jul 2005 03:43:21 -0000
*************** s390_gimplify_va_arg (tree valist, tree 
*** 7309,7315 ****
      t = build2 (PLUS_EXPR, ptr_type_node, t, 
  		fold_convert (ptr_type_node, size_int (UNITS_PER_WORD - size)));
  
!   gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
  
    u = build2 (MODIFY_EXPR, void_type_node, addr, t);
    gimplify_and_add (u, pre_p);
--- 7309,7315 ----
      t = build2 (PLUS_EXPR, ptr_type_node, t, 
  		fold_convert (ptr_type_node, size_int (UNITS_PER_WORD - size)));
  
!   gimplify_to_operand (t, pre_p, NULL, &t, false);
  
    u = build2 (MODIFY_EXPR, void_type_node, addr, t);
    gimplify_and_add (u, pre_p);
Index: config/sparc/sparc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.c,v
retrieving revision 1.381
diff -c -3 -p -r1.381 sparc.c
*** config/sparc/sparc.c	6 Jul 2005 07:48:58 -0000	1.381
--- config/sparc/sparc.c	22 Jul 2005 03:43:28 -0000
*************** sparc_gimplify_va_arg (tree valist, tree
*** 5570,5576 ****
  			   ssize_int (-align)));
      }
  
!   gimplify_expr (&incr, pre_p, post_p, is_gimple_val, fb_rvalue);
    addr = incr;
  
    if (BYTES_BIG_ENDIAN && size < rsize)
--- 5570,5576 ----
  			   ssize_int (-align)));
      }
  
!   gimplify_to_operand (incr, pre_p, post_p, &incr, false);
    addr = incr;
  
    if (BYTES_BIG_ENDIAN && size < rsize)
Index: config/stormy16/stormy16.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/stormy16/stormy16.c,v
retrieving revision 1.80
diff -c -3 -p -r1.80 stormy16.c
*** config/stormy16/stormy16.c	12 Jul 2005 03:48:20 -0000	1.80
--- config/stormy16/stormy16.c	22 Jul 2005 03:43:31 -0000
*************** xstormy16_expand_builtin_va_arg (tree va
*** 1409,1415 ****
  
    must_stack = targetm.calls.must_pass_in_stack (TYPE_MODE (type), type);
    size_tree = round_up (size_in_bytes (type), UNITS_PER_WORD);
!   gimplify_expr (&size_tree, pre_p, NULL, is_gimple_val, fb_rvalue);
    
    size_of_reg_args = NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD;
  
--- 1409,1415 ----
  
    must_stack = targetm.calls.must_pass_in_stack (TYPE_MODE (type), type);
    size_tree = round_up (size_in_bytes (type), UNITS_PER_WORD);
!   gimplify_to_operand (size_tree, pre_p, NULL, &size_tree, false);
    
    size_of_reg_args = NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD;
  
Index: config/xtensa/xtensa.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/xtensa/xtensa.c,v
retrieving revision 1.77
diff -c -3 -p -r1.77 xtensa.c
*** config/xtensa/xtensa.c	12 Jul 2005 03:48:20 -0000	1.77
--- config/xtensa/xtensa.c	22 Jul 2005 03:43:33 -0000
*************** xtensa_gimplify_va_arg_expr (tree valist
*** 2171,2177 ****
  
    type_size = size_in_bytes (type);
    va_size = round_up (type_size, UNITS_PER_WORD);
!   gimplify_expr (&va_size, pre_p, NULL, is_gimple_val, fb_rvalue);
  
  
    /* First align __va_ndx if necessary for this arg:
--- 2171,2177 ----
  
    type_size = size_in_bytes (type);
    va_size = round_up (type_size, UNITS_PER_WORD);
!   gimplify_to_operand (va_size, pre_p, NULL, &va_size, false);
  
  
    /* First align __va_ndx if necessary for this arg:
Index: cp/cp-gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-gimplify.c,v
retrieving revision 1.23
diff -c -3 -p -r1.23 cp-gimplify.c
*** cp/cp-gimplify.c	25 Jun 2005 00:58:09 -0000	1.23
--- cp/cp-gimplify.c	22 Jul 2005 03:43:34 -0000
*************** gimplify_cp_loop (tree cond, tree body, 
*** 287,299 ****
  static void
  gimplify_for_stmt (tree *stmt_p, tree *pre_p)
  {
!   tree stmt = *stmt_p;
  
    if (FOR_INIT_STMT (stmt))
      gimplify_and_add (FOR_INIT_STMT (stmt), pre_p);
  
!   *stmt_p = gimplify_cp_loop (FOR_COND (stmt), FOR_BODY (stmt),
! 			      FOR_EXPR (stmt), 1);
  }
  
  /* Gimplify a WHILE_STMT node.  */
--- 287,301 ----
  static void
  gimplify_for_stmt (tree *stmt_p, tree *pre_p)
  {
!   tree stmt = *stmt_p, stmts;
  
    if (FOR_INIT_STMT (stmt))
      gimplify_and_add (FOR_INIT_STMT (stmt), pre_p);
  
!   stmts = gimplify_cp_loop (FOR_COND (stmt), FOR_BODY (stmt),
! 			    FOR_EXPR (stmt), 1);
!   append_to_statement_list (stmts, pre_p);
!   *stmt_p = NULL_TREE;
  }
  
  /* Gimplify a WHILE_STMT node.  */
*************** cp_gimplify_init_expr (tree *expr_p, tre
*** 404,410 ****
       case we want to replace the INIT_EXPR.  */
    if (TREE_CODE (sub) == AGGR_INIT_EXPR)
      {
!       gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
        TREE_OPERAND (sub, 2) = to;
        *expr_p = from;
  
--- 406,412 ----
       case we want to replace the INIT_EXPR.  */
    if (TREE_CODE (sub) == AGGR_INIT_EXPR)
      {
!       gimplify_to_lhs (to, pre_p, post_p, &to);
        TREE_OPERAND (sub, 2) = to;
        *expr_p = from;
  
*************** cp_gimplify_expr (tree *expr_p, tree *pr
*** 513,519 ****
      case USING_STMT:
        /* Just ignore for now.  Eventually we will want to pass this on to
  	 the debugger.  */
!       *expr_p = build_empty_stmt ();
        ret = GS_ALL_DONE;
        break;
  
--- 515,521 ----
      case USING_STMT:
        /* Just ignore for now.  Eventually we will want to pass this on to
  	 the debugger.  */
!       *expr_p = NULL_TREE;
        ret = GS_ALL_DONE;
        break;
  
*************** cp_gimplify_expr (tree *expr_p, tree *pr
*** 529,554 ****
  
      case WHILE_STMT:
        gimplify_while_stmt (expr_p);
        ret = GS_ALL_DONE;
        break;
  
      case DO_STMT:
        gimplify_do_stmt (expr_p);
        ret = GS_ALL_DONE;
        break;
  
      case SWITCH_STMT:
        gimplify_switch_stmt (expr_p);
        ret = GS_ALL_DONE;
        break;
  
      case CONTINUE_STMT:
!       *expr_p = build_bc_goto (bc_continue);
        ret = GS_ALL_DONE;
        break;
  
      case BREAK_STMT:
!       *expr_p = build_bc_goto (bc_break);
        ret = GS_ALL_DONE;
        break;
  
--- 531,564 ----
  
      case WHILE_STMT:
        gimplify_while_stmt (expr_p);
+       append_to_statement_list (*expr_p, pre_p);
+       *expr_p = NULL_TREE;
        ret = GS_ALL_DONE;
        break;
  
      case DO_STMT:
        gimplify_do_stmt (expr_p);
+       append_to_statement_list (*expr_p, pre_p);
+       *expr_p = NULL_TREE;
        ret = GS_ALL_DONE;
        break;
  
      case SWITCH_STMT:
        gimplify_switch_stmt (expr_p);
+       append_to_statement_list (*expr_p, pre_p);
+       *expr_p = NULL_TREE;
        ret = GS_ALL_DONE;
        break;
  
      case CONTINUE_STMT:
!       append_to_statement_list (build_bc_goto (bc_continue), pre_p);
!       *expr_p = NULL_TREE;
        ret = GS_ALL_DONE;
        break;
  
      case BREAK_STMT:
!       append_to_statement_list (build_bc_goto (bc_break), pre_p);
!       *expr_p = NULL_TREE;
        ret = GS_ALL_DONE;
        break;
  
Index: doc/passes.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/passes.texi,v
retrieving revision 1.55
diff -c -3 -p -r1.55 passes.texi
*** doc/passes.texi	4 Jun 2005 17:07:57 -0000	1.55
--- doc/passes.texi	22 Jul 2005 03:43:35 -0000
*************** Usually it is easier to generate GENERIC
*** 122,133 ****
  and let the language-independent gimplifier do most of the work.
  
  @findex gimplify_function_tree
! @findex gimplify_expr
  @findex lang_hooks.gimplify_expr
  The main entry point to this pass is @code{gimplify_function_tree}
  located in @file{gimplify.c}.  From here we process the entire
  function gimplifying each statement in turn.  The main workhorse
! for this pass is @code{gimplify_expr}.  Approximately everything
  passes through here at least once, and it is from here that we
  invoke the @code{lang_hooks.gimplify_expr} callback.
  
--- 122,133 ----
  and let the language-independent gimplifier do most of the work.
  
  @findex gimplify_function_tree
! @findex gimplify_main
  @findex lang_hooks.gimplify_expr
  The main entry point to this pass is @code{gimplify_function_tree}
  located in @file{gimplify.c}.  From here we process the entire
  function gimplifying each statement in turn.  The main workhorse
! for this pass is @code{gimplify_main}.  Approximately everything
  passes through here at least once, and it is from here that we
  invoke the @code{lang_hooks.gimplify_expr} callback.
  
Index: doc/tm.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/tm.texi,v
retrieving revision 1.443
diff -c -3 -p -r1.443 tm.texi
*** doc/tm.texi	21 Jul 2005 00:55:20 -0000	1.443
--- doc/tm.texi	22 Jul 2005 03:43:50 -0000
*************** The default version of the hook returns 
*** 3824,3830 ****
  This hook performs target-specific gimplification of
  @code{VA_ARG_EXPR}.  The first two parameters correspond to the
  arguments to @code{va_arg}; the latter two are as in
! @code{gimplify.c:gimplify_expr}.
  @end deftypefn
  
  @deftypefn {Target Hook} bool TARGET_VALID_POINTER_MODE (enum machine_mode @var{mode})
--- 3824,3830 ----
  This hook performs target-specific gimplification of
  @code{VA_ARG_EXPR}.  The first two parameters correspond to the
  arguments to @code{va_arg}; the latter two are as in
! @code{gimplify.c:gimplify_main}.
  @end deftypefn
  
  @deftypefn {Target Hook} bool TARGET_VALID_POINTER_MODE (enum machine_mode @var{mode})
Index: java/java-gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-gimplify.c,v
retrieving revision 1.20
diff -c -3 -p -r1.20 java-gimplify.c
*** java/java-gimplify.c	20 Jul 2005 01:19:42 -0000	1.20
--- java/java-gimplify.c	22 Jul 2005 03:43:50 -0000
*************** java_gimplify_expr (tree *expr_p, tree *
*** 163,170 ****
  	  || TREE_CODE_CLASS (code) == tcc_comparison)
  	{
  	  enum gimplify_status stat 
! 	    = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 			     is_gimple_formal_tmp_var, fb_rvalue);
  	  if (stat == GS_ERROR)
  	    return stat;
  	}
--- 163,170 ----
  	  || TREE_CODE_CLASS (code) == tcc_comparison)
  	{
  	  enum gimplify_status stat 
! 	    = gimplify_to_operand (TREE_OPERAND (*expr_p, 0), pre_p, post_p,
! 				   &TREE_OPERAND (*expr_p, 0), true);
  	  if (stat == GS_ERROR)
  	    return stat;
  	}
Index: objc/objc-act.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.288
diff -c -3 -p -r1.288 objc-act.c
*** objc/objc-act.c	20 Jul 2005 01:19:49 -0000	1.288
--- objc/objc-act.c	22 Jul 2005 03:43:57 -0000
*************** objc_gimplify_expr (tree *expr_p, tree *
*** 9483,9492 ****
  	 OBJ_TYPE_REF. This permits objc_msgSend calls in Objective
  	 C to use direct rather than indirect calls when the
  	 object expression has a postincrement.  */
!       r0 = gimplify_expr (&OBJ_TYPE_REF_OBJECT (*expr_p), pre_p, NULL,
! 			  is_gimple_val, fb_rvalue);
!       r1 = gimplify_expr (&OBJ_TYPE_REF_EXPR (*expr_p), pre_p, post_p,
! 			  is_gimple_val, fb_rvalue);
  
        return MIN (r0, r1);
      }
--- 9483,9492 ----
  	 OBJ_TYPE_REF. This permits objc_msgSend calls in Objective
  	 C to use direct rather than indirect calls when the
  	 object expression has a postincrement.  */
!       r0 = gimplify_to_operand (OBJ_TYPE_REF_OBJECT (*expr_p), pre_p, NULL,
! 				&OBJ_TYPE_REF_OBJECT (*expr_p), false);
!       r1 = gimplify_to_operand (OBJ_TYPE_REF_EXPR (*expr_p), pre_p, post_p,
! 				&OBJ_TYPE_REF_EXPR (*expr_p), false);
  
        return MIN (r0, r1);
      }


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