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: Gimplify VA_ARG_EXPR


This patch introduces a new target hook for gimplifying VA_ARG_EXPR, namely
TARGET_GIMPLIFY_VA_ARG_EXPR.  This will need to be defined everywhere
EXPAND_BUILTIN_VA_ARG is currently defined.  I've written and tested
implementations for x86, ia64 and ppc.  I've also written an implementation
for sparc, but don't have a sparc64 box handy for testing, so I've left it
disabled until someone has a chance to test it.

Converting the code for the va_arg expander to work as a gimplifier is
pretty straightforward, and I'm happy to answer any questions that port
maintainers might have.

Targets that do not define the new hook will continue to use the fallback
strategy of marking everything under the VA_ARG_EXPR as volatile.

One difference between the expanders and the gimplifiers is that the
expander returns an address which is then dereferenced by
expand_builtin_va_arg, whereas the gimplifier does the dereference itself.
This seemed like the right choice to me since gimplification involves
clobbering things in place, but the other choice would simplify the code
for complex numbers on PPC a bit.  This would be easy enough to change now;
thoughts?

The new build_fold_* functions seem generally useful; it occurred to me to
wonder why fold doesn't already do that sort of transformation.  Making
that change broke bootstrap, however, and I didn't feel like following up.

Tested x86-linux-gnu, x86_64-linux-gnu, powerpc64-linux-gnu,
ia64-linux-gnu.  Fixes gcc.dg/va-arg-3.c.

I'll apply it in the morning unless someone screams.

2004-06-08  Jason Merrill  <jason@redhat.com>

	Gimplify VA_ARG_EXPR into simpler forms.
	* target.h: Add gimplify_va_arg_expr hook.
	* target-def.h: Add TARGET_GIMPLIFY_VA_ARG_EXPR.
	* fold-const.c (build_fold_addr_expr)
	(build_fold_addr_expr_with_type): Move from gimplify.c.
	* tree.h: Declare them.
	* gimplify.c (gimplify_and_add): New fn.
	(build_addr_expr, build_addr_expr_with_type): Move to fold-const.c.
	(gimplify_array_ref_to_plus, gimplify_modify_expr)
	(gimplify_expr): Use build_fold_*.
	(copy_if_shared_r): Only mark VA_ARG_EXPR volatile if we
	don't know how to gimplify it.
	* builtins.c (std_gimplify_va_arg_expr): New fn.
	(dummy_object): New static fn.
	(gimplify_va_arg_expr): New fn.
	(stabilize_va_list): Use build_fold_*.
	* tree-gimple.h: Declare new fns.
	* config/i386/i386.c (TARGET_GIMPLIFY_VA_ARG_EXPR): Define.
	(ix86_gimplify_va_arg): New fn.
	* config/i386/ia64.c (TARGET_GIMPLIFY_VA_ARG_EXPR): Define.
	(ia64_gimplify_va_arg): New fn.
	* config/i386/rs6000.c (rs6000_gimplify_va_arg): New fn.
	(TARGET_GIMPLIFY_VA_ARG_EXPR): Define.
	* config/i386/sparc.c (sparc_gimplify_va_arg): New fn.
	* alias.c (get_varargs_alias_set): Just return 0 for now.
	
	* c-objc-common.c (c_tree_printer): Improve handling of %T.

2004-06-08  Alexandre Oliva  <aoliva@redhat.com>

	* gimplify.c (copy_if_shared_r): Revert:
	2004-05-21  Richard Henderson  <rth@redhat.com>
	* gimplify.c [...] Don't mark VA_ARG_EXPRs volatile here.

*** ./alias.c.~1~	2004-06-03 16:26:18.000000000 -0400
--- ./alias.c	2004-06-03 16:25:19.000000000 -0400
*************** static GTY(()) HOST_WIDE_INT varargs_set
*** 737,746 ****
--- 737,754 ----
  HOST_WIDE_INT
  get_varargs_alias_set (void)
  {
+ #if 1
+   /* We now lower VA_ARG_EXPR, and there's currently no way to attach the
+      varargs alias set to an INDIRECT_REF (FIXME!), so we can't
+      consistently use the varargs alias set for loads from the varargs
+      area.  So don't use it anywhere.  */
+   return 0;
+ #else
    if (varargs_set == -1)
      varargs_set = new_alias_set ();
  
    return varargs_set;
+ #endif
  }
  
  /* Likewise, but used for the fixed portions of the frame, e.g., register
*** ./config/i386/i386.c.~1~	2004-06-03 16:26:18.000000000 -0400
--- ./config/i386/i386.c	2004-06-08 16:29:35.000000000 -0400
*************** Boston, MA 02111-1307, USA.  */
*** 46,51 ****
--- 46,52 ----
  #include "target-def.h"
  #include "langhooks.h"
  #include "cgraph.h"
+ #include "tree-gimple.h"
  
  #ifndef CHECK_STACK_LIMIT
  #define CHECK_STACK_LIMIT (-1)
*************** static bool ix86_expand_carry_flag_compa
*** 877,882 ****
--- 878,884 ----
  static tree ix86_build_builtin_va_list (void);
  static void ix86_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
  					 tree, int *, int);
+ static void ix86_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p);
  
  struct ix86_address
  {
*************** static void init_ext_80387_constants (vo
*** 1069,1074 ****
--- 1071,1079 ----
  #undef TARGET_SETUP_INCOMING_VARARGS
  #define TARGET_SETUP_INCOMING_VARARGS ix86_setup_incoming_varargs
  
+ #undef TARGET_GIMPLIFY_VA_ARG_EXPR
+ #define TARGET_GIMPLIFY_VA_ARG_EXPR ix86_gimplify_va_arg
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  
*************** ix86_va_arg (tree valist, tree type)
*** 3410,3415 ****
--- 3415,3672 ----
  
    return addr_rtx;
  }
+ 
+ /* Lower VA_ARG_EXPR at gimplification time.  */
+ 
+ void
+ ix86_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p)
+ {
+   tree valist = TREE_OPERAND (*expr_p, 0);
+   tree type = TREE_TYPE (*expr_p);
+   static const int intreg[6] = { 0, 1, 2, 3, 4, 5 };
+   tree f_gpr, f_fpr, f_ovf, f_sav;
+   tree gpr, fpr, ovf, sav, t;
+   int size, rsize;
+   tree lab_false, lab_over = NULL_TREE;
+   tree addr, t2;
+   rtx container;
+   int indirect_p = 0;
+   tree ptrtype;
+ 
+   /* Only 64bit target needs something special.  */
+   if (!TARGET_64BIT)
+     {
+       std_gimplify_va_arg_expr (expr_p, pre_p, post_p);
+       return;
+     }
+ 
+   f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+   f_fpr = TREE_CHAIN (f_gpr);
+   f_ovf = TREE_CHAIN (f_fpr);
+   f_sav = TREE_CHAIN (f_ovf);
+ 
+   valist = build_fold_indirect_ref (valist);
+   gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+   fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+   ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
+   sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+ 
+   size = int_size_in_bytes (type);
+   if (size == -1)
+     {
+       /* Variable-size types are passed by reference.  */
+       indirect_p = 1;
+       type = build_pointer_type (type);
+       size = int_size_in_bytes (type);
+     }
+   rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ 
+   container = construct_container (TYPE_MODE (type), type, 0,
+ 				   REGPARM_MAX, SSE_REGPARM_MAX, intreg, 0);
+   /*
+    * Pull the value out of the saved registers ...
+    */
+ 
+   addr = create_tmp_var (ptr_type_node, "addr");
+   DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set ();
+ 
+   if (container)
+     {
+       int needed_intregs, needed_sseregs;
+       int need_temp;
+       tree int_addr, sse_addr;
+ 
+       lab_false = create_artificial_label ();
+       lab_over = create_artificial_label ();
+ 
+       examine_argument (TYPE_MODE (type), type, 0,
+ 		        &needed_intregs, &needed_sseregs);
+ 
+ 
+       need_temp = ((needed_intregs && TYPE_ALIGN (type) > 64)
+ 		   || TYPE_ALIGN (type) > 128);
+ 
+       /* In case we are passing structure, verify that it is consecutive block
+          on the register save area.  If not we need to do moves.  */
+       if (!need_temp && !REG_P (container))
+ 	{
+ 	  /* Verify that all registers are strictly consecutive  */
+ 	  if (SSE_REGNO_P (REGNO (XEXP (XVECEXP (container, 0, 0), 0))))
+ 	    {
+ 	      int i;
+ 
+ 	      for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++)
+ 		{
+ 		  rtx slot = XVECEXP (container, 0, i);
+ 		  if (REGNO (XEXP (slot, 0)) != FIRST_SSE_REG + (unsigned int) i
+ 		      || INTVAL (XEXP (slot, 1)) != i * 16)
+ 		    need_temp = 1;
+ 		}
+ 	    }
+ 	  else
+ 	    {
+ 	      int i;
+ 
+ 	      for (i = 0; i < XVECLEN (container, 0) && !need_temp; i++)
+ 		{
+ 		  rtx slot = XVECEXP (container, 0, i);
+ 		  if (REGNO (XEXP (slot, 0)) != (unsigned int) i
+ 		      || INTVAL (XEXP (slot, 1)) != i * 8)
+ 		    need_temp = 1;
+ 		}
+ 	    }
+ 	}
+       if (!need_temp)
+ 	{
+ 	  int_addr = addr;
+ 	  sse_addr = addr;
+ 	}
+       else
+ 	{
+ 	  int_addr = create_tmp_var (ptr_type_node, "int_addr");
+ 	  DECL_POINTER_ALIAS_SET (int_addr) = get_varargs_alias_set ();
+ 	  sse_addr = create_tmp_var (ptr_type_node, "sse_addr");
+ 	  DECL_POINTER_ALIAS_SET (sse_addr) = get_varargs_alias_set ();
+ 	}
+       /* First ensure that we fit completely in registers.  */
+       if (needed_intregs)
+ 	{
+ 	  t = build_int_2 ((REGPARM_MAX - needed_intregs + 1) * 8, 0);
+ 	  TREE_TYPE (t) = TREE_TYPE (gpr);
+ 	  t = build2 (GE_EXPR, boolean_type_node, gpr, t);
+ 	  t2 = build1 (GOTO_EXPR, void_type_node, lab_false);
+ 	  t = build (COND_EXPR, void_type_node, t, t2, NULL_TREE);
+ 	  gimplify_and_add (t, pre_p);
+ 	}
+       if (needed_sseregs)
+ 	{
+ 	  t = build_int_2 ((SSE_REGPARM_MAX - needed_sseregs + 1) * 16
+ 			   + REGPARM_MAX * 8, 0);
+ 	  TREE_TYPE (t) = TREE_TYPE (fpr);
+ 	  t = build2 (GE_EXPR, boolean_type_node, fpr, t);
+ 	  t2 = build1 (GOTO_EXPR, void_type_node, lab_false);
+ 	  t = build (COND_EXPR, void_type_node, t, t2, NULL_TREE);
+ 	  gimplify_and_add (t, pre_p);
+ 	}
+ 
+       /* Compute index to start of area used for integer regs.  */
+       if (needed_intregs)
+ 	{
+ 	  /* int_addr = gpr + sav; */
+ 	  t = build2 (PLUS_EXPR, ptr_type_node, sav, gpr);
+ 	  t = build2 (MODIFY_EXPR, void_type_node, int_addr, t);
+ 	  gimplify_and_add (t, pre_p);
+ 	}
+       if (needed_sseregs)
+ 	{
+ 	  /* sse_addr = fpr + sav; */
+ 	  t = build2 (PLUS_EXPR, ptr_type_node, sav, fpr);
+ 	  t = build2 (MODIFY_EXPR, void_type_node, sse_addr, t);
+ 	  gimplify_and_add (t, pre_p);
+ 	}
+       if (need_temp)
+ 	{
+ 	  int i;
+ 	  tree temp = create_tmp_var (type, "va_arg_tmp");
+ 
+ 	  /* addr = &temp; */
+ 	  t = build1 (ADDR_EXPR, build_pointer_type (type), temp);
+ 	  t = build2 (MODIFY_EXPR, void_type_node, addr, t);
+ 	  gimplify_and_add (t, pre_p);
+ 	  
+ 	  for (i = 0; i < XVECLEN (container, 0); i++)
+ 	    {
+ 	      rtx slot = XVECEXP (container, 0, i);
+ 	      rtx reg = XEXP (slot, 0);
+ 	      enum machine_mode mode = GET_MODE (reg);
+ 	      tree piece_type = lang_hooks.types.type_for_mode (mode, 1);
+ 	      tree addr_type = build_pointer_type (piece_type);
+ 	      tree src_addr, src;
+ 	      int src_offset;
+ 	      tree dest_addr, dest;
+ 
+ 	      if (SSE_REGNO_P (REGNO (reg)))
+ 		{
+ 		  src_addr = sse_addr;
+ 		  src_offset = (REGNO (reg) - FIRST_SSE_REG) * 16;
+ 		}
+ 	      else
+ 		{
+ 		  src_addr = int_addr;
+ 		  src_offset = REGNO (reg) * 8;
+ 		}
+ 	      src_addr = convert (addr_type, src_addr);
+ 	      src_addr = fold (build2 (PLUS_EXPR, addr_type, src_addr,
+ 				       size_int (src_offset)));
+ 	      src = build_fold_indirect_ref (src_addr);
+ 
+ 	      dest_addr = convert (addr_type, addr);
+ 	      dest_addr = fold (build2 (PLUS_EXPR, addr_type, dest_addr,
+ 					size_int (INTVAL (XEXP (slot, 1)))));
+ 	      dest = build_fold_indirect_ref (dest_addr);
+ 
+ 	      t = build2 (MODIFY_EXPR, void_type_node, dest, src);
+ 	      gimplify_and_add (t, pre_p);
+ 	    }
+ 	}
+ 
+       if (needed_intregs)
+ 	{
+ 	  t = build2 (PLUS_EXPR, TREE_TYPE (gpr), gpr,
+ 		      build_int_2 (needed_intregs * 8, 0));
+ 	  t = build2 (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t);
+ 	  gimplify_and_add (t, pre_p);
+ 	}
+       if (needed_sseregs)
+ 	{
+ 	  t =
+ 	    build2 (PLUS_EXPR, TREE_TYPE (fpr), fpr,
+ 		   build_int_2 (needed_sseregs * 16, 0));
+ 	  t = build2 (MODIFY_EXPR, TREE_TYPE (fpr), fpr, t);
+ 	  gimplify_and_add (t, pre_p);
+ 	}
+ 
+       t = build1 (GOTO_EXPR, void_type_node, lab_over);
+       gimplify_and_add (t, pre_p);
+ 
+       t = build1 (LABEL_EXPR, void_type_node, lab_false);
+       append_to_statement_list (t, pre_p);
+     }
+ 
+   /* ... otherwise out of the overflow area.  */
+ 
+   /* Care for on-stack alignment if needed.  */
+   if (FUNCTION_ARG_BOUNDARY (VOIDmode, type) <= 64)
+     t = ovf;
+   else
+     {
+       HOST_WIDE_INT align = FUNCTION_ARG_BOUNDARY (VOIDmode, type) / 8;
+       t = build (PLUS_EXPR, TREE_TYPE (ovf), ovf, build_int_2 (align - 1, 0));
+       t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
+     }
+   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);
+ 
+   t = build2 (PLUS_EXPR, TREE_TYPE (t), t,
+ 	      build_int_2 (rsize * UNITS_PER_WORD, 0));
+   t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
+   gimplify_and_add (t, pre_p);
+ 
+   if (container)
+     {
+       t = build1 (LABEL_EXPR, void_type_node, lab_over);
+       append_to_statement_list (t, pre_p);
+     }
+ 
+   ptrtype = build_pointer_type (type);
+   addr = convert (ptrtype, addr);
+ 
+   if (indirect_p)
+     addr = build_fold_indirect_ref (addr);
+   *expr_p = build_fold_indirect_ref (addr);
+ }
  
  /* Return nonzero if OP is either a i387 or SSE fp register.  */
  int
*** ./config/ia64/ia64.c.~1~	2004-06-03 16:26:18.000000000 -0400
--- ./config/ia64/ia64.c	2004-06-08 16:36:59.000000000 -0400
*************** Boston, MA 02111-1307, USA.  */
*** 51,56 ****
--- 51,57 ----
  #include "hashtab.h"
  #include "langhooks.h"
  #include "cfglayout.h"
+ #include "tree-gimple.h"
  
  /* This is used for communication between ASM_OUTPUT_LABEL and
     ASM_OUTPUT_LABELREF.  */
*************** static void ia64_vms_init_libfuncs (void
*** 273,278 ****
--- 274,280 ----
  static tree ia64_handle_model_attribute (tree *, tree, tree, int, bool *);
  static void ia64_encode_section_info (tree, rtx, int);
  static rtx ia64_struct_value_rtx (tree, int);
+ static void ia64_gimplify_va_arg (tree *, tree *, tree *);
  
  
  /* Table of valid machine attributes.  */
*************** static const struct attribute_spec ia64_
*** 407,412 ****
--- 409,417 ----
  #undef TARGET_STRICT_ARGUMENT_NAMING
  #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
  
+ #undef TARGET_GIMPLIFY_VA_ARG_EXPR
+ #define TARGET_GIMPLIFY_VA_ARG_EXPR ia64_gimplify_va_arg
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  /* Return 1 if OP is a valid operand for the MEM of a CALL insn.  */
*************** ia64_va_arg (tree valist, tree type)
*** 3987,3992 ****
--- 3992,4030 ----
  
    return std_expand_builtin_va_arg (valist, type);
  }
+ 
+ static void
+ ia64_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p)
+ {
+   tree valist = TREE_OPERAND (*expr_p, 0);
+   tree type = TREE_TYPE (*expr_p);
+ 
+   /* Variable sized types are passed by reference.  */
+   if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+     {
+       TREE_TYPE (*expr_p) = build_pointer_type (type);
+       std_gimplify_va_arg_expr (expr_p, pre_p, post_p);
+       *expr_p = build_fold_indirect_ref (*expr_p);
+       return;
+     }
+ 
+   /* Aggregate arguments with alignment larger than 8 bytes start at
+      the next even boundary.  Integer and floating point arguments
+      do so if they are larger than 8 bytes, whether or not they are
+      also aligned larger than 8 bytes.  */
+   if ((TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == INTEGER_TYPE)
+       ? int_size_in_bytes (type) > 8 : TYPE_ALIGN (type) > 8 * BITS_PER_UNIT)
+     {
+       tree t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
+ 		      build_int_2 (2 * UNITS_PER_WORD - 1, 0));
+       t = build (BIT_AND_EXPR, TREE_TYPE (t), t,
+ 		 build_int_2 (-2 * UNITS_PER_WORD, -1));
+       t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
+       gimplify_and_add (t, pre_p);
+     }
+ 
+   std_gimplify_va_arg_expr (expr_p, pre_p, post_p);
+ }
  
  /* Return 1 if function return value returned in memory.  Return 0 if it is
     in a register.  */
*** ./config/rs6000/rs6000.c.~1~	2004-06-03 16:26:18.000000000 -0400
--- ./config/rs6000/rs6000.c	2004-06-09 00:41:59.000000000 -0400
***************
*** 52,57 ****
--- 52,58 ----
  #include "reload.h"
  #include "cfglayout.h"
  #include "sched-int.h"
+ #include "tree-gimple.h"
  #if TARGET_XCOFF
  #include "xcoffout.h"  /* get declarations of xcoff_*_section_name */
  #endif
*************** static tree get_prev_label (tree functio
*** 439,444 ****
--- 440,446 ----
  #endif
  
  static tree rs6000_build_builtin_va_list (void);
+ static void rs6000_gimplify_va_arg (tree *, tree *, tree *);
  
  /* Hash table stuff for keeping track of TOC entries.  */
  
*************** static const char alt_reg_names[][8] =
*** 647,652 ****
--- 649,657 ----
  #undef TARGET_BUILD_BUILTIN_VA_LIST
  #define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list
  
+ #undef TARGET_GIMPLIFY_VA_ARG_EXPR
+ #define TARGET_GIMPLIFY_VA_ARG_EXPR rs6000_gimplify_va_arg
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  
*************** rs6000_va_arg (tree valist, tree type)
*** 5287,5292 ****
--- 5292,5534 ----
    return addr_rtx;
  }
  
+ void
+ rs6000_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p)
+ {
+   tree valist = TREE_OPERAND (*expr_p, 0);
+   tree type = TREE_TYPE (*expr_p);
+   tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
+   tree gpr, fpr, ovf, sav, reg, t, u;
+   int indirect_p, size, rsize, n_reg, sav_ofs, sav_scale;
+   tree lab_false, lab_over, addr;
+   int align;
+   tree ptrtype = build_pointer_type (type);
+ 
+   if (DEFAULT_ABI != ABI_V4)
+     {
+       /* Variable sized types are passed by reference, as are AltiVec
+ 	 vectors when 32-bit and not using the AltiVec ABI extension.  */
+       if (int_size_in_bytes (type) < 0
+ 	  || (TARGET_32BIT
+ 	      && !TARGET_ALTIVEC_ABI
+ 	      && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))))
+ 	{
+ 	  /* Args grow upward.  */
+ 	  t = build2 (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist,
+ 		      build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
+ 	  t = build1 (NOP_EXPR, build_pointer_type (ptrtype), t);
+ 	  t = build_fold_indirect_ref (t);
+ 	  t = build_fold_indirect_ref (t);
+ 
+ 	  *expr_p = t;
+ 	  return;
+ 	}
+       if (targetm.calls.split_complex_arg
+ 	  && TREE_CODE (type) == COMPLEX_TYPE)
+ 	{
+ 	  tree elem_type = TREE_TYPE (type);
+ 	  enum machine_mode elem_mode = TYPE_MODE (elem_type);
+ 	  int elem_size = GET_MODE_SIZE (elem_mode);
+ 
+ 	  if (elem_size < UNITS_PER_WORD)
+ 	    {
+ 	      tree real_part, imag_addr, dest_real, rr;
+ 	      tree post = NULL_TREE;
+ 
+ 	      /* This is a bit tricky because we can't just feed the
+ 		 VA_ARG_EXPRs back into gimplify_expr; if we did,
+ 		 gimplify_va_arg_expr would complain about trying to pass a
+ 		 float. */
+ 	      real_part = build1 (VA_ARG_EXPR, elem_type, valist);
+ 	      rs6000_gimplify_va_arg (&real_part, pre_p, &post);
+ 	      gimplify_expr (&real_part, pre_p, &post, is_gimple_val,
+ 			     fb_rvalue);
+ 	      append_to_statement_list (post, pre_p);
+ 
+ 	      imag_addr = build1 (VA_ARG_EXPR, elem_type, valist);
+ 	      rs6000_gimplify_va_arg (&imag_addr, pre_p, post_p);
+ 	      imag_addr = build_fold_addr_expr (imag_addr);
+ 	      gimplify_expr (&imag_addr, pre_p, post_p, is_gimple_val,
+ 			     fb_rvalue);
+ 
+ 	      /* We're not returning the value here, but the address.
+ 		 real_part and imag_part are not contiguous, and we know
+ 		 there is space available to pack real_part next to
+ 		 imag_part.  float _Complex is not promoted to
+ 		 double _Complex by the default promotion rules that
+ 		 promote float to double.  */
+ 	      if (2 * elem_size > UNITS_PER_WORD)
+ 		abort ();
+ 
+ 	      dest_real = fold (build2 (MINUS_EXPR, TREE_TYPE (imag_addr),
+ 					imag_addr, ssize_int (elem_size)));
+ 	      gimplify_expr (&dest_real, pre_p, post_p, is_gimple_val,
+ 			     fb_rvalue);
+ 
+ 	      rr = build_fold_indirect_ref (dest_real);
+ 	      rr = build2 (MODIFY_EXPR, void_type_node, rr, real_part);
+ 	      gimplify_and_add (rr, pre_p);
+ 
+ 	      dest_real = convert (build_pointer_type (type), dest_real);
+ 	      *expr_p = build_fold_indirect_ref (dest_real);
+ 
+ 	      return;
+ 	    }
+ 	}
+ 
+       std_gimplify_va_arg_expr (expr_p, pre_p, post_p);
+       return;
+     }
+ 
+   f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
+   f_fpr = TREE_CHAIN (f_gpr);
+   f_res = TREE_CHAIN (f_fpr);
+   f_ovf = TREE_CHAIN (f_res);
+   f_sav = TREE_CHAIN (f_ovf);
+ 
+   valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
+   gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
+   fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
+   ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
+   sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
+ 
+   size = int_size_in_bytes (type);
+   rsize = (size + 3) / 4;
+   align = 1;
+ 
+   if (AGGREGATE_TYPE_P (type)
+       || TYPE_MODE (type) == TFmode
+       || (!TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))))
+     {
+       /* Aggregates, long doubles, and AltiVec vectors are passed by
+ 	 reference.  */
+       indirect_p = 1;
+       reg = gpr;
+       n_reg = 1;
+       sav_ofs = 0;
+       sav_scale = 4;
+       size = 4;
+       rsize = 1;
+     }
+   else if (TARGET_HARD_FLOAT && TARGET_FPRS
+ 	   && (TYPE_MODE (type) == SFmode || TYPE_MODE (type) == DFmode))
+     {
+       /* FP args go in FP registers, if present.  */
+       indirect_p = 0;
+       reg = fpr;
+       n_reg = 1;
+       sav_ofs = 8*4;
+       sav_scale = 8;
+       if (TYPE_MODE (type) == DFmode)
+ 	align = 8;
+     }
+   else
+     {
+       /* Otherwise into GP registers.  */
+       indirect_p = 0;
+       reg = gpr;
+       n_reg = rsize;
+       sav_ofs = 0;
+       sav_scale = 4;
+       if (n_reg == 2)
+ 	align = 8;
+     }
+ 
+   /* Pull the value out of the saved registers....  */
+ 
+   lab_over = NULL;
+   addr = create_tmp_var (ptr_type_node, "addr");
+   DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set ();
+ 
+   /*  AltiVec vectors never go in registers when -mabi=altivec.  */
+   if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
+     align = 16;
+   else
+     {
+       lab_false = create_artificial_label ();
+       lab_over = create_artificial_label ();
+ 
+       /* Long long and SPE vectors are aligned in the registers.
+ 	 As are any other 2 gpr item such as complex int due to a
+ 	 historical mistake.  */
+       u = reg;
+       if (n_reg == 2)
+ 	{
+ 	  u = build2 (BIT_AND_EXPR, TREE_TYPE (reg), reg,
+ 		     build_int_2 (n_reg - 1, 0));
+ 	  u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, u);
+ 	}
+ 
+       t = build_int_2 (8 - n_reg + 1, 0);
+       TREE_TYPE (t) = TREE_TYPE (reg);
+       t = build2 (GE_EXPR, boolean_type_node, u, t);
+       u = build1 (GOTO_EXPR, void_type_node, lab_false);
+       t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
+       gimplify_and_add (t, pre_p);
+ 
+       t = sav;
+       if (sav_ofs)
+ 	t = build2 (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0));
+ 
+       u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg,
+ 		 build_int_2 (n_reg, 0));
+       u = build1 (CONVERT_EXPR, integer_type_node, u);
+       u = build2 (MULT_EXPR, integer_type_node, u, build_int_2 (sav_scale, 0));
+       t = build2 (PLUS_EXPR, ptr_type_node, t, u);
+ 
+       t = build2 (MODIFY_EXPR, void_type_node, addr, t);
+       gimplify_and_add (t, pre_p);
+ 
+       t = build1 (GOTO_EXPR, void_type_node, lab_over);
+       gimplify_and_add (t, pre_p);
+ 
+       t = build1 (LABEL_EXPR, void_type_node, lab_false);
+       append_to_statement_list (t, pre_p);
+ 
+       if (n_reg > 2)
+ 	{
+ 	  /* Ensure that we don't find any more args in regs.
+ 	     Alignment has taken care of the n_reg == 2 case.  */
+ 	  t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, build_int_2 (8, 0));
+ 	  gimplify_and_add (t, pre_p);
+ 	}
+     }
+ 
+   /* ... otherwise out of the overflow area.  */
+ 
+   /* Care for on-stack alignment if needed.  */
+   t = ovf;
+   if (align != 1)
+     {
+       t = build2 (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (align - 1, 0));
+       t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
+     }
+   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);
+ 
+   t = build2 (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0));
+   t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
+   gimplify_and_add (t, pre_p);
+ 
+   if (lab_over)
+     {
+       t = build1 (LABEL_EXPR, void_type_node, lab_over);
+       append_to_statement_list (t, pre_p);
+     }
+ 
+   if (indirect_p)
+     {
+       addr = convert (build_pointer_type (ptrtype), addr);
+       addr = build_fold_indirect_ref (addr);
+     }
+   else
+     addr = convert (ptrtype, addr);
+ 
+   *expr_p = build_fold_indirect_ref (addr);
+ }
+ 
  /* Builtins.  */
  
  #define def_builtin(MASK, NAME, TYPE, CODE)			\
*** ./config/sparc/sparc.c.~1~	2004-06-03 16:26:18.000000000 -0400
--- ./config/sparc/sparc.c	2004-06-09 00:52:36.000000000 -0400
*************** Boston, MA 02111-1307, USA.  */
*** 47,52 ****
--- 47,53 ----
  #include "target.h"
  #include "target-def.h"
  #include "cfglayout.h"
+ #include "tree-gimple.h"
  
  /* Global variables for machine-dependent things.  */
  
*************** static bool sparc_promote_prototypes (tr
*** 181,186 ****
--- 182,190 ----
  static rtx sparc_struct_value_rtx (tree, int);
  static bool sparc_return_in_memory (tree, tree);
  static bool sparc_strict_argument_naming (CUMULATIVE_ARGS *);
+ #if 0
+ static void sparc_gimplify_va_arg (tree *, tree *, tree *);
+ #endif
  
  /* Option handling.  */
  
*************** enum processor_type sparc_cpu;
*** 289,294 ****
--- 293,303 ----
  #undef TARGET_STRICT_ARGUMENT_NAMING
  #define TARGET_STRICT_ARGUMENT_NAMING sparc_strict_argument_naming
  
+ #if 0
+ #undef TARGET_GIMPLIFY_VA_ARG_EXPR
+ #define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg
+ #endif
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  /* Validate and override various options, and do some machine dependent
*************** sparc_va_arg (tree valist, tree type)
*** 6042,6047 ****
--- 6051,6155 ----
  
    return addr_rtx;
  }
+ 
+ #if 0
+ void
+ sparc_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p)
+ {
+   tree valist = TREE_OPERAND (*expr_p, 0);
+   tree type = TREE_TYPE (*expr_p);
+   HOST_WIDE_INT size, rsize, align;
+   tree addr, incr;
+   bool indirect;
+   tree ptrtype = build_pointer_type (type);
+ 
+   if (function_arg_pass_by_reference (0, TYPE_MODE (type), type, 0))
+     {
+       indirect = true;
+       size = rsize = UNITS_PER_WORD;
+       align = 0;
+     }
+   else
+     {
+       indirect = false;
+       size = int_size_in_bytes (type);
+       rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
+       align = 0;
+     
+       if (TARGET_ARCH64)
+ 	{
+ 	  /* For SPARC64, objects requiring 16-byte alignment get it.  */
+ 	  if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD)
+ 	    align = 2 * UNITS_PER_WORD;
+ 
+ 	  /* SPARC-V9 ABI states that structures up to 16 bytes in size
+ 	     are given whole slots as needed.  */
+ 	  if (AGGREGATE_TYPE_P (type))
+ 	    {
+ 	      if (size == 0)
+ 		size = rsize = UNITS_PER_WORD;
+ 	      else
+ 		size = rsize;
+ 	    }
+ 	}
+     }
+ 
+   incr = valist;
+   if (align)
+     {
+       incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr,
+ 			   build_int_2 (align - 1, 0)));
+       incr = fold (build2 (BIT_AND_EXPR, ptr_type_node, incr,
+ 			   build_int_2 (-align, -1)));
+     }
+ 
+   gimplify_expr (&incr, pre_p, post_p, is_gimple_val, fb_rvalue);
+   addr = incr;
+ 
+   if (BYTES_BIG_ENDIAN && size < rsize)
+     {
+       addr = fold (build2 (PLUS_EXPR, ptr_type_node, incr,
+ 			   build_int_2 (rsize - size, 0)));
+     }
+   incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr,
+ 		       build_int_2 (rsize, 0)));
+ 
+   incr = build2 (MODIFY_EXPR, ptr_type_node, valist, incr);
+   gimplify_and_add (incr, pre_p);
+ 
+   if (indirect)
+     {
+       addr = convert (build_pointer_type (ptrtype), addr);
+       addr = build_fold_indirect_ref (addr);
+     }
+   /* If the address isn't aligned properly for the type,
+      we may need to copy to a temporary.  
+      FIXME: This is inefficient.  Usually we can do this
+      in registers.  */
+   else if (align == 0
+ 	   && TYPE_ALIGN (type) > BITS_PER_WORD)
+     {
+       tree tmp = create_tmp_var (type, "va_arg_tmp");
+       tree dest_addr = build1 (ADDR_EXPR, build_pointer_type (type), tmp);
+ 
+       incr = build_function_call_expr
+ 	(implicit_built_in_decls[BUILT_IN_MEMCPY],
+ 	 tree_cons (NULL_TREE, dest_addr,
+ 		    tree_cons (NULL_TREE, addr,
+ 			       tree_cons (NULL_TREE, size_int (rsize),
+ 					  NULL_TREE))));
+       gimplify_and_add (incr, pre_p);
+       *expr_p = tmp;
+       return GS_ALL_DONE;
+     }
+ 
+   if (!indirect)
+     addr = convert (build_pointer_type (type), addr);
+   *expr_p = build_fold_indirect_ref (addr);
+ 
+   return false;
+ }
+ #endif
  
  /* Return the string to output a conditional branch to LABEL, which is
     the operand number of the label.  OP is the conditional expression.
*** ./doc/tm.texi.~1~	2004-05-25 16:03:40.000000000 -0400
--- ./doc/tm.texi	2004-06-08 17:04:12.000000000 -0400
*************** The default value of this hook is @code{
*** 3864,3869 ****
--- 3864,3881 ----
  false.
  @end deftypefn
  
+ @deftypefn {Target Hook} bool TARGET_GIMPLIFY_VA_ARG_EXPR (tree *@var{expr_p}, tree *@var{pre_p}, tree *@var{post_p})
+ This hook performs target-specific gimplification of
+ @code{VA_ARG_EXPR}.  The arguments are as for
+ @code{gimplify.c:gimplify_expr}.
+ 
+ You only need to define this hook if you also define
+ @code{EXPAND_BUILTIN_VA_ARG}; it is pretty easy to reuse the same code
+ for both.  One significant difference is that
+ @code{EXPAND_BUILTIN_VA_ARG} returns an address, whereas this hook
+ produces a reference, usually an @code{INDIRECT_REF}.
+ @end deftypefn
+ 
  @node Scalar Return
  @subsection How Scalar Function Values Are Returned
  @cindex return values in registers
*** ./builtins.c.~1~	2004-06-03 16:26:18.000000000 -0400
--- ./builtins.c	2004-06-08 16:37:12.000000000 -0400
*************** stabilize_va_list (tree valist, int need
*** 4102,4111 ****
        if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
  	{
  	  tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
! 	  tree p2 = build_pointer_type (va_list_type_node);
! 
! 	  valist = build1 (ADDR_EXPR, p2, valist);
! 	  valist = fold_convert (p1, valist);
  	}
      }
    else
--- 4102,4108 ----
        if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
  	{
  	  tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
! 	  valist = build_fold_addr_expr_with_type (valist, p1);
  	}
      }
    else
*************** stabilize_va_list (tree valist, int need
*** 4124,4131 ****
  
        if (TREE_SIDE_EFFECTS (valist))
  	valist = save_expr (valist);
!       valist = fold (build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)),
! 			     valist));
      }
  
    return valist;
--- 4121,4127 ----
  
        if (TREE_SIDE_EFFECTS (valist))
  	valist = save_expr (valist);
!       valist = build_fold_indirect_ref (valist);
      }
  
    return valist;
*************** expand_builtin_va_arg (tree valist, tree
*** 4360,4365 ****
--- 4356,4539 ----
    return result;
  }
  
+ /* Like std_expand_builtin_va_arg, but gimplify instead of expanding.  */
+ 
+ void
+ std_gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
+ {
+   tree addr, t, type_size = NULL;
+   tree align, alignm1;
+   tree rounded_size;
+   HOST_WIDE_INT boundary;
+   tree valist = TREE_OPERAND (*expr_p, 0);
+   tree type = TREE_TYPE (*expr_p);
+ 
+   /* Compute the rounded size of the type.  */
+   align = size_int (PARM_BOUNDARY / BITS_PER_UNIT);
+   alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1);
+   boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type);
+ 
+   /* Reduce valist it so it's sharable with the postqueue.  */
+   gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
+ 
+   /* va_list pointer is aligned to PARM_BOUNDARY.  If argument actually
+      requires greater alignment, we must perform dynamic alignment.  */
+ 
+   if (boundary > PARM_BOUNDARY)
+     {
+       if (!PAD_VARARGS_DOWN)
+ 	{
+ 	  t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
+ 		      build2 (PLUS_EXPR, TREE_TYPE (valist), valist,
+ 			      build_int_2 (boundary / BITS_PER_UNIT - 1, 0)));
+ 	  gimplify_stmt (&t);
+ 	  append_to_statement_list (t, pre_p);
+ 	}
+       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
+ 		  build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist,
+ 			  build_int_2 (~(boundary / BITS_PER_UNIT - 1), -1)));
+       gimplify_stmt (&t);
+       append_to_statement_list (t, pre_p);
+     }
+   if (type == error_mark_node
+       || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
+       || TREE_OVERFLOW (type_size))
+     rounded_size = size_zero_node;
+   else
+     {
+       rounded_size = fold (build2 (PLUS_EXPR, sizetype, type_size, alignm1));
+       rounded_size = fold (build2 (TRUNC_DIV_EXPR, sizetype,
+ 				   rounded_size, align));
+       rounded_size = fold (build2 (MULT_EXPR, sizetype,
+ 				   rounded_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;
+   if (PAD_VARARGS_DOWN && ! integer_zerop (rounded_size))
+     {
+       /* Small args are padded downward.  */
+       addr = fold (build2 (PLUS_EXPR, TREE_TYPE (addr), addr,
+ 				fold (build3 (COND_EXPR, sizetype,
+ 					      fold (build2 (GT_EXPR, sizetype,
+ 							    rounded_size,
+ 							    align)),
+ 					      size_zero_node,
+ 					      fold (build2 (MINUS_EXPR,
+ 							    sizetype,
+ 							    rounded_size,
+ 							    type_size))))));
+     }
+ 
+   addr = convert (build_pointer_type (type), addr);
+   *expr_p = build1 (INDIRECT_REF, type, addr);
+ 
+   /* Compute new value for AP.  */
+   if (! integer_zerop (rounded_size))
+     {
+       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
+ 		  build2 (PLUS_EXPR, TREE_TYPE (valist), valist,
+ 			  rounded_size));
+       gimplify_stmt (&t);
+       append_to_statement_list (t, post_p);
+     }
+ }
+ 
+ /* Return a dummy expression of type TYPE in order to keep going after an
+    error.  */
+ 
+ static tree
+ dummy_object (tree type)
+ {
+   tree t = convert (build_pointer_type (type), null_pointer_node);
+   return build1 (INDIRECT_REF, type, t);
+ }
+ 
+ /* Like expand_builtin_va_arg, but gimplify instead of expanding.  */
+ 
+ enum gimplify_status
+ gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
+ {
+   tree promoted_type, want_va_type, have_va_type;
+   tree valist = TREE_OPERAND (*expr_p, 0);
+   tree type = TREE_TYPE (*expr_p);
+   tree t;
+ 
+   /* Verify that valist is of the proper type.  */
+ 
+   want_va_type = va_list_type_node;
+   have_va_type = TREE_TYPE (valist);
+   if (TREE_CODE (want_va_type) == ARRAY_TYPE)
+     {
+       /* If va_list is an array type, the argument may have decayed
+ 	 to a pointer type, e.g. by being passed to another function.
+          In that case, unwrap both types so that we can compare the
+ 	 underlying records.  */
+       if (TREE_CODE (have_va_type) == ARRAY_TYPE
+ 	  || TREE_CODE (have_va_type) == POINTER_TYPE)
+ 	{
+ 	  want_va_type = TREE_TYPE (want_va_type);
+ 	  have_va_type = TREE_TYPE (have_va_type);
+ 	}
+     }
+ 
+   if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type))
+     {
+       error ("first argument to `va_arg' not of type `va_list'");
+       *expr_p = dummy_object (type);
+       return GS_ALL_DONE;
+     }
+ 
+   /* Generate a diagnostic for requesting data of a type that cannot
+      be passed through `...' due to type promotion at the call site.  */
+   else if ((promoted_type = lang_hooks.types.type_promotes_to (type))
+ 	   != type)
+     {
+       static bool gave_help;
+ 
+       /* Unfortunately, this is merely undefined, rather than a constraint
+ 	 violation, so we cannot make this an error.  If this call is never
+ 	 executed, the program is still strictly conforming.  */
+       warning ("`%T' is promoted to `%T' when passed through `...'",
+ 	       type, promoted_type);
+       if (! gave_help)
+ 	{
+ 	  gave_help = true;
+ 	  warning ("(so you should pass `%T' not `%T' to `va_arg')",
+ 		   promoted_type, type);
+ 	}
+ 
+       /* We can, however, treat "undefined" any way we please.
+ 	 Call abort to encourage the user to fix the program.  */
+       inform ("if this code is reached, the program will abort");
+       t = build_function_call_expr (implicit_built_in_decls[BUILT_IN_TRAP],
+ 				    NULL);
+       append_to_statement_list (t, pre_p);
+ 
+       /* This is dead code, but go ahead and finish so that the
+ 	 mode of the result comes out right.  */
+       *expr_p = dummy_object (type);
+       return GS_ALL_DONE;
+     }
+   else
+     {
+       /* Make it easier for the backends by protecting the valist argument
+          from multiple evaluations.  */
+       valist = stabilize_va_list (valist, 0);
+       TREE_OPERAND (*expr_p, 0) = valist;
+ 
+       if (!targetm.calls.gimplify_va_arg_expr)
+ 	/* Once most targets are converted this should abort.  */
+ 	return GS_ALL_DONE;
+ 
+       targetm.calls.gimplify_va_arg_expr (expr_p, pre_p, post_p);
+       return GS_OK;
+     }
+ }
+ 
  /* Expand ARGLIST, from a call to __builtin_va_end.  */
  
  static rtx
*** ./gimplify.c.~1~	2004-06-03 16:26:18.000000000 -0400
--- ./gimplify.c	2004-06-08 11:55:20.000000000 -0400
*************** Software Foundation, 59 Temple Place - S
*** 45,50 ****
--- 45,51 ----
  #include "output.h"
  #include "expr.h"
  #include "ggc.h"
+ #include "target.h"
  
  static struct gimplify_ctx
  {
*************** append_to_statement_list_force (tree t, 
*** 236,241 ****
--- 237,251 ----
    append_to_statement_list_1 (t, list_p, t != NULL);
  }
  
+ /* 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);
+ }
+ 
  /* Add T to the end of a COMPOUND_EXPR pointed by LIST_P.  The type
     of the result is the type of T.  */
  
*************** copy_if_shared_r (tree *tp, int *walk_su
*** 665,671 ****
  
    /* Otherwise, mark the tree as visited and keep looking.  */
    else
!     TREE_VISITED (t) = 1;
  
    return NULL_TREE;
  }
--- 675,697 ----
  
    /* Otherwise, mark the tree as visited and keep looking.  */
    else
!     {
!       TREE_VISITED (t) = 1;
!       if (TREE_CODE (*tp) == VA_ARG_EXPR
! 	  && targetm.calls.gimplify_va_arg_expr == NULL)
! 	{
! 	  /* Mark any _DECL inside the operand as volatile to avoid
! 	     the optimizers messing around with it. We have to do this
! 	     early, otherwise we might mark a variable as volatile
! 	     after we gimplify other statements that use the variable
! 	     assuming it's not volatile.  */
! 
! 	  /* FIXME once most targets define the above hook, this should
! 	     go away (perhaps along with the #include "target.h").  */
! 	  walk_tree (&TREE_OPERAND (*tp, 0), mark_decls_volatile_r,
! 		     NULL, NULL);
! 	}
!     }
  
    return NULL_TREE;
  }
*************** gimplify_minimax_expr (tree *expr_p, tre
*** 1636,1674 ****
      return GS_OK;
  }
  
- /*  Build an expression for the address of T.  Folds away INDIRECT_REF to
-     avoid confusing the gimplify process.  */
- 
- static tree
- build_addr_expr_with_type (tree t, tree ptrtype)
- {
-   if (TREE_CODE (t) == INDIRECT_REF)
-     {
-       t = TREE_OPERAND (t, 0);
-       if (TREE_TYPE (t) != ptrtype)
- 	t = build1 (NOP_EXPR, ptrtype, t);
-     }
-   else
-     {
-       tree base = t;
-       while (TREE_CODE (base) == COMPONENT_REF
- 	     || TREE_CODE (base) == ARRAY_REF)
- 	base = TREE_OPERAND (base, 0);
-       if (DECL_P (base))
- 	TREE_ADDRESSABLE (base) = 1;
- 
-       t = build1 (ADDR_EXPR, ptrtype, t);
-     }
- 
-   return t;
- }
- 
- static tree
- build_addr_expr (tree t)
- {
-   return build_addr_expr_with_type (t, build_pointer_type (TREE_TYPE (t)));
- }
- 
  /* Subroutine of gimplify_compound_lval and gimplify_array_ref.
     Converts an ARRAY_REF to the equivalent *(&array + offset) form.  */
  
--- 1662,1667 ----
*************** gimplify_array_ref_to_plus (tree *expr_p
*** 1719,1725 ****
    if (ret == GS_ERROR)
      return ret;
  
!   addr = build_addr_expr_with_type (array, ptrtype);
    result = fold (build (add_code, ptrtype, addr, offset));
    *expr_p = build1 (INDIRECT_REF, elttype, result);
  
--- 1712,1718 ----
    if (ret == GS_ERROR)
      return ret;
  
!   addr = build_fold_addr_expr_with_type (array, ptrtype);
    result = fold (build (add_code, ptrtype, addr, offset));
    *expr_p = build1 (INDIRECT_REF, elttype, result);
  
*************** gimplify_modify_expr (tree *expr_p, tree
*** 2536,2544 ****
  	  t = TYPE_SIZE_UNIT (TREE_TYPE (*to_p));
  	  t = unshare_expr (t);
  	  args = tree_cons (NULL, t, NULL);
! 	  t = build_addr_expr (*from_p);
  	  args = tree_cons (NULL, t, args);
! 	  dest = build_addr_expr (*to_p);
  	  args = tree_cons (NULL, dest, args);
  	  t = implicit_built_in_decls[BUILT_IN_MEMCPY];
  	  t = build_function_call_expr (t, args);
--- 2529,2537 ----
  	  t = TYPE_SIZE_UNIT (TREE_TYPE (*to_p));
  	  t = unshare_expr (t);
  	  args = tree_cons (NULL, t, NULL);
! 	  t = build_fold_addr_expr (*from_p);
  	  args = tree_cons (NULL, t, args);
! 	  dest = build_fold_addr_expr (*to_p);
  	  args = tree_cons (NULL, dest, args);
  	  t = implicit_built_in_decls[BUILT_IN_MEMCPY];
  	  t = build_function_call_expr (t, args);
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 3242,3255 ****
  	  break;
  
  	case VA_ARG_EXPR:
! 	  /* Mark any _DECL inside the operand as volatile to avoid the
! 	     optimizers messing around with it. FIXME: Remove this once
! 	     VA_ARG_EXPRs are properly lowered.  */
! 	  walk_tree (&TREE_OPERAND (*expr_p, 0), mark_decls_volatile_r,
! 		     NULL, NULL);
! 
! 	  /* va_arg expressions are in GIMPLE form already.  */
! 	  ret = GS_ALL_DONE;
  	  break;
  
  	case CONVERT_EXPR:
--- 3235,3241 ----
  	  break;
  
  	case VA_ARG_EXPR:
! 	  ret = gimplify_va_arg_expr (expr_p, pre_p, post_p);
  	  break;
  
  	case CONVERT_EXPR:
*************** gimplify_expr (tree *expr_p, tree *pre_p
*** 3589,3595 ****
        /* 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_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);
      }
--- 3575,3581 ----
        /* 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);
      }
*** ./target-def.h.~1~	2004-06-03 16:26:18.000000000 -0400
--- ./target-def.h	2004-06-07 15:54:38.000000000 -0400
*************** Foundation, 59 Temple Place - Suite 330,
*** 358,363 ****
--- 358,371 ----
    default_pretend_outgoing_varargs_named
  #define TARGET_SPLIT_COMPLEX_ARG NULL
  
+ #ifdef EXPAND_BUILTIN_VA_ARG
+ /* If there's a target-specific va_arg expander, there needs to be a
+    target-specific gimplifier.  */
+ #define TARGET_GIMPLIFY_VA_ARG_EXPR NULL
+ #else
+ #define TARGET_GIMPLIFY_VA_ARG_EXPR std_gimplify_va_arg_expr
+ #endif
+ 
  #define TARGET_CALLS {						\
     TARGET_PROMOTE_FUNCTION_ARGS,				\
     TARGET_PROMOTE_FUNCTION_RETURN,				\
*************** Foundation, 59 Temple Place - Suite 330,
*** 370,375 ****
--- 378,384 ----
     TARGET_STRICT_ARGUMENT_NAMING,				\
     TARGET_PRETEND_OUTGOING_VARARGS_NAMED,			\
     TARGET_SPLIT_COMPLEX_ARG,					\
+    TARGET_GIMPLIFY_VA_ARG_EXPR,					\
     }
  
  /* The whole shebang.  */
*** ./c-objc-common.c.~1~	2004-06-03 16:26:18.000000000 -0400
--- ./c-objc-common.c	2004-06-03 16:25:21.000000000 -0400
*************** c_tree_printer (pretty_printer *pp, text
*** 270,286 ****
        break;
  
      case 'T':
!       if (TREE_CODE (t) == TYPE_DECL)
  	{
  	  if (DECL_NAME (t))
  	    n = lang_hooks.decl_printable_name (t, 2);
  	}
!       else
! 	{
! 	  t = TYPE_NAME (t);
! 	  if (t)
! 	    n = IDENTIFIER_POINTER (t);
! 	}
        break;
  
      case 'E':
--- 270,284 ----
        break;
  
      case 'T':
!       if (TYPE_P (t))
! 	t = TYPE_NAME (t);
!       if (t && TREE_CODE (t) == TYPE_DECL)
  	{
  	  if (DECL_NAME (t))
  	    n = lang_hooks.decl_printable_name (t, 2);
  	}
!       else if (t)
! 	n = IDENTIFIER_POINTER (t);
        break;
  
      case 'E':
*** ./target.h.~1~	2004-06-03 16:26:18.000000000 -0400
--- ./target.h	2004-06-08 16:28:49.000000000 -0400
*************** struct gcc_target
*** 470,475 ****
--- 470,479 ----
      /* Given a complex type T, return true if a parameter of type T
         should be passed as two scalars.  */
      bool (* split_complex_arg) (tree type);
+ 
+     /* Gimplifies a VA_ARG_EXPR.  */
+     void (* gimplify_va_arg_expr) (tree *expr_p, tree *pre_p,
+ 				   tree *post_p);
    } calls;
  
    /* Leave the boolean fields at the end.  */
*** ./tree.h.~1~	2004-06-03 16:26:18.000000000 -0400
--- ./tree.h	2004-06-04 14:47:31.000000000 -0400
*************** struct tree_block GTY(())
*** 1602,1608 ****
  #define TYPE_VECTOR_SUBPARTS(VECTOR_TYPE) \
    GET_MODE_NUNITS (VECTOR_TYPE_CHECK (VECTOR_TYPE)->type.mode)
  
!   /* Indicates that objects of this type must be initialized by calling a
     function when they are created.  */
  #define TYPE_NEEDS_CONSTRUCTING(NODE) \
    (TYPE_CHECK (NODE)->type.needs_constructing_flag)
--- 1602,1608 ----
  #define TYPE_VECTOR_SUBPARTS(VECTOR_TYPE) \
    GET_MODE_NUNITS (VECTOR_TYPE_CHECK (VECTOR_TYPE)->type.mode)
  
! /* Indicates that objects of this type must be initialized by calling a
     function when they are created.  */
  #define TYPE_NEEDS_CONSTRUCTING(NODE) \
    (TYPE_CHECK (NODE)->type.needs_constructing_flag)
*************** extern tree nondestructive_fold_unary_to
*** 3473,3478 ****
--- 3473,3481 ----
  extern tree nondestructive_fold_binary_to_constant (enum tree_code, tree, tree, tree);
  extern tree fold_read_from_constant_string (tree);
  extern tree int_const_binop (enum tree_code, tree, tree, int);
+ extern tree build_fold_addr_expr (tree);
+ extern tree build_fold_addr_expr_with_type (tree, tree);
+ extern tree build_fold_indirect_ref (tree);
  
  /* In builtins.c */
  extern tree fold_builtin (tree);
*** ./tree-gimple.h.~1~	2004-06-03 16:26:18.000000000 -0400
--- ./tree-gimple.h	2004-06-08 17:05:19.000000000 -0400
*************** void gimplify_to_stmt_list (tree *);
*** 107,112 ****
--- 107,113 ----
  void gimplify_body (tree *, tree);
  void push_gimplify_context (void);
  void pop_gimplify_context (tree);
+ void gimplify_and_add (tree, tree *);
  
  /* Miscellaneous helpers.  */
  tree get_base_address (tree t);
*************** tree build_and_jump (tree *);
*** 121,126 ****
--- 122,129 ----
  tree alloc_stmt_list (void);
  void free_stmt_list (tree);
  tree force_labels_r (tree *, int *, void *);
+ enum gimplify_status gimplify_va_arg_expr (tree *, tree *, tree *);
+ void std_gimplify_va_arg_expr (tree *, tree *, tree *);
  
  /* In tree-nested.c.  */
  extern void lower_nested_functions (tree);
*** ./fold-const.c.~1~	2004-06-01 10:57:37.000000000 -0400
--- ./fold-const.c	2004-06-07 15:23:16.000000000 -0400
*************** fold_relational_const (enum tree_code co
*** 9994,9997 ****
--- 9994,10066 ----
    return tem;
  }
  
+ /* Build an expression for the address of T.  Folds away INDIRECT_REF to
+    avoid confusing the gimplify process.  */
+ 
+ tree
+ build_fold_addr_expr_with_type (tree t, tree ptrtype)
+ {
+   if (TREE_CODE (t) == INDIRECT_REF)
+     {
+       t = TREE_OPERAND (t, 0);
+       if (TREE_TYPE (t) != ptrtype)
+ 	t = build1 (NOP_EXPR, ptrtype, t);
+     }
+   else
+     {
+       tree base = t;
+       while (TREE_CODE (base) == COMPONENT_REF
+ 	     || TREE_CODE (base) == ARRAY_REF)
+ 	base = TREE_OPERAND (base, 0);
+       if (DECL_P (base))
+ 	TREE_ADDRESSABLE (base) = 1;
+ 
+       t = build1 (ADDR_EXPR, ptrtype, t);
+     }
+ 
+   return t;
+ }
+ 
+ tree
+ build_fold_addr_expr (tree t)
+ {
+   return build_fold_addr_expr_with_type (t, build_pointer_type (TREE_TYPE (t)));
+ }
+ 
+ /* Builds an expression for an indirection through T, simplifying some
+    cases.  */
+ 
+ tree
+ build_fold_indirect_ref (tree t)
+ {
+   tree type = TREE_TYPE (TREE_TYPE (t));
+   tree sub = t;
+   tree subtype;
+ 
+   STRIP_NOPS (sub);
+   if (TREE_CODE (sub) == ADDR_EXPR)
+     {
+       tree op = TREE_OPERAND (sub, 0);
+       tree optype = TREE_TYPE (op);
+       /* *&p => p */
+       if (lang_hooks.types_compatible_p (type, optype))
+ 	return op;
+       /* *(foo *)&fooarray => fooarray[0] */
+       else if (TREE_CODE (optype) == ARRAY_TYPE
+ 	       && lang_hooks.types_compatible_p (type, TREE_TYPE (optype)))
+ 	return build2 (ARRAY_REF, type, op, size_zero_node);
+     }
+ 
+   /* *(foo *)fooarrptr => (*fooarrptr)[0] */
+   subtype = TREE_TYPE (sub);
+   if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
+       && lang_hooks.types_compatible_p (type, TREE_TYPE (TREE_TYPE (subtype))))
+     {
+       sub = build_fold_indirect_ref (sub);
+       return build2 (ARRAY_REF, type, sub, size_zero_node);
+     }
+ 
+   return build1 (INDIRECT_REF, type, t);
+ }
+ 
  #include "gt-fold-const.h"

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