public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* PATCH: Gimplify VA_ARG_EXPR
@ 2004-06-09  7:21 Jason Merrill
  2004-06-09 21:39 ` Richard Henderson
  0 siblings, 1 reply; 6+ messages in thread
From: Jason Merrill @ 2004-06-09  7:21 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2986 bytes --]

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.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-patch, Size: 46875 bytes --]

*** ./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;
  
  \f
*************** 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);
+ }
  \f
  /* 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 *);
  
  \f
  /* 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;
  \f
  /* 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);
+ }
  \f
  /* 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;
  \f
  
*************** 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
  \f
  /* 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;
  \f
  /* 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
  \f
  /* 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"

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: Gimplify VA_ARG_EXPR
  2004-06-09  7:21 PATCH: Gimplify VA_ARG_EXPR Jason Merrill
@ 2004-06-09 21:39 ` Richard Henderson
  2004-06-09 22:01   ` Jason Merrill
  0 siblings, 1 reply; 6+ messages in thread
From: Richard Henderson @ 2004-06-09 21:39 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On Wed, Jun 09, 2004 at 01:05:34AM -0400, Jason Merrill wrote:
> +   tree valist = TREE_OPERAND (*expr_p, 0);
...
> +   valist = build_fold_indirect_ref (valist);

The argument to va_arg_expr isn't a pointer.

> +   addr = create_tmp_var (ptr_type_node, "addr");
> +   DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set ();

Alias set on the decl and not the type?  Isn't this going to be
(potentially) broken by gimplification?

> +   tree t = convert (build_pointer_type (type), null_pointer_node);

fold_convert.

> +       /* Make it easier for the backends by protecting the valist argument
> +          from multiple evaluations.  */
> +       valist = stabilize_va_list (valist, 0);

Seems like the min_value thing would be better here.


r~

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: Gimplify VA_ARG_EXPR
  2004-06-09 21:39 ` Richard Henderson
@ 2004-06-09 22:01   ` Jason Merrill
  2004-06-09 22:30     ` Richard Henderson
  0 siblings, 1 reply; 6+ messages in thread
From: Jason Merrill @ 2004-06-09 22:01 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches

On Wed, 9 Jun 2004 13:07:16 -0700, Richard Henderson <rth@redhat.com> wrote:

> On Wed, Jun 09, 2004 at 01:05:34AM -0400, Jason Merrill wrote:
>> +   tree valist = TREE_OPERAND (*expr_p, 0);
> ...
>> +   valist = build_fold_indirect_ref (valist);
>
> The argument to va_arg_expr isn't a pointer.

If you're referring to the use in ix86_gimplify_va_arg, the expander does
the same thing.  On x86_64 the argument is too a pointer, generated in
stabilize_va_list.

>
>> +   addr = create_tmp_var (ptr_type_node, "addr");
>> +   DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set ();
>
> Alias set on the decl and not the type?  Isn't this going to be
> (potentially) broken by gimplification?

The alias bit dates from before I gave up on getting the varargs alias set
to work right now.  I figured it was harmless and might as well leave it in.

>> +   tree t = convert (build_pointer_type (type), null_pointer_node);
>
> fold_convert.

OK, thanks.

>> +       /* Make it easier for the backends by protecting the valist argument
>> +          from multiple evaluations.  */
>> +       valist = stabilize_va_list (valist, 0);
>
> Seems like the min_value thing would be better here.

stabilize_va_list predates this patch.  I tried moving the min_lval bit
from std_gimplify_va_arg_expr to here, but it broke on x86_64 because
valist is an ADDR_EXPR.  I could poke at that some more if you think it's
warranted.

Jason

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: PATCH: Gimplify VA_ARG_EXPR
  2004-06-09 22:01   ` Jason Merrill
@ 2004-06-09 22:30     ` Richard Henderson
  2004-06-10 17:54       ` followup " Jason Merrill
  0 siblings, 1 reply; 6+ messages in thread
From: Richard Henderson @ 2004-06-09 22:30 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On Wed, Jun 09, 2004 at 04:44:25PM -0400, Jason Merrill wrote:
> If you're referring to the use in ix86_gimplify_va_arg, the expander does
> the same thing.  On x86_64 the argument is too a pointer, generated in
> stabilize_va_list.

Oh, I forgot amd64 had the silly __va_list[1] thing.  Sorry.

> stabilize_va_list predates this patch.  I tried moving the min_lval bit
> from std_gimplify_va_arg_expr to here, but it broke on x86_64 because
> valist is an ADDR_EXPR.  I could poke at that some more if you think it's
> warranted.

*shrug* I was just thinking that direct gimplification would be
less wasteful than creating SAVE_EXPRs.  But for now it's probably
easiest to leave it alone.


r~

^ permalink raw reply	[flat|nested] 6+ messages in thread

* followup PATCH: Gimplify VA_ARG_EXPR
  2004-06-09 22:30     ` Richard Henderson
@ 2004-06-10 17:54       ` Jason Merrill
  2004-06-14  5:51         ` Jason Merrill
  0 siblings, 1 reply; 6+ messages in thread
From: Jason Merrill @ 2004-06-10 17:54 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1030 bytes --]

This patch implements some of rth's suggestions, and changes the signature
of the hook to take the valist and type as args and return the object.

Tested x86_64-pc-linux-gnu, ia64-pc-linux-gnu, powerpc64-pc-linux-gnu.  Now
testing (slowly) on sparc-sun-solaris9; I'll commit that hook once it
finishes.  rth, can you verify that the alpha hook still works after this
patch?

Applied to trunk.

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

	* target.h (struct gcc_target): Change gimplify_va_arg_expr 
	hook signature.
	* tree-gimple.h: Adjust.
	* config/alpha/alpha.c (alpha_gimplify_va_arg): Adjust.
	* config/i386/i386.c (ix86_gimplify_va_arg): Adjust.
	Use fold_convert.
	* config/ia64/ia64.c (ia64_gimplify_va_arg): Adjust.
	* config/rs6000/rs6000.c (rs6000_gimplify_va_arg): Adjust.
	Use COMPLEX_EXPR for complex numbers.  Use fold_convert.
	* builtins.c (std_gimplify_va_arg_expr): Adjust.  Use fold_convert.
	(gimplify_va_arg_expr): Return GS_ERROR in error case.
	Gimplify valist rather than calling stabilize_va_list.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-patch, Size: 26366 bytes --]

*** ./target.h.~1~	2004-06-09 15:26:36.000000000 -0400
--- ./target.h	2004-06-09 23:57:29.000000000 -0400
*************** struct gcc_target
*** 472,478 ****
      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;
  
--- 472,478 ----
      bool (* split_complex_arg) (tree type);
  
      /* Gimplifies a VA_ARG_EXPR.  */
!     tree (* gimplify_va_arg_expr) (tree valist, tree type, tree *pre_p,
  				   tree *post_p);
    } calls;
  
*** ./config/alpha/alpha.c.~1~	2004-06-09 17:49:25.000000000 -0400
--- ./config/alpha/alpha.c	2004-06-10 01:34:02.000000000 -0400
*************** alpha_gimplify_va_arg_1 (tree type, tree
*** 6444,6460 ****
    else if (TREE_CODE (type) == COMPLEX_TYPE)
      {
        tree real_part, imag_part, real_temp;
  
        real_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, offset,
! 					   pre_p, post_p);
!       append_to_statement_list (*post_p, pre_p);
!       *post_p = NULL;
! 
        /* Copy the value into a temporary, lest the formal temporary
  	 be reused out from under us.  */
!       real_temp = create_tmp_var (TREE_TYPE (real_part), NULL);
!       t = build (MODIFY_EXPR, void_type_node, real_temp, real_part);
!       gimplify_and_add (t, pre_p);
  
        imag_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, offset,
  					   pre_p, post_p);
--- 6444,6457 ----
    else if (TREE_CODE (type) == COMPLEX_TYPE)
      {
        tree real_part, imag_part, real_temp;
+       tree post = NULL_TREE;
  
        real_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, offset,
! 					   pre_p, &post);
        /* Copy the value into a temporary, lest the formal temporary
  	 be reused out from under us.  */
!       real_temp = get_initialized_tmp_var (real_part, pre_p, &post);
!       append_to_statement_list (post, pre_p);
  
        imag_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base, offset,
  					   pre_p, post_p);
*************** alpha_gimplify_va_arg_1 (tree type, tree
*** 6491,6509 ****
    return build_fold_indirect_ref (addr);
  }
  
! static void
! alpha_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p)
  {
!   tree valist, type, offset_field, base_field, offset, base, t;
  
    if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
!     {
!       std_gimplify_va_arg_expr (expr_p, pre_p, post_p);
!       return;
!     }
! 
!   valist = TREE_OPERAND (*expr_p, 0);
!   type = TREE_TYPE (*expr_p);
  
    base_field = TYPE_FIELDS (va_list_type_node);
    offset_field = TREE_CHAIN (base_field);
--- 6488,6500 ----
    return build_fold_indirect_ref (addr);
  }
  
! static tree
! alpha_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
  {
!   tree offset_field, base_field, offset, base, t, r;
  
    if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
!     return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
  
    base_field = TYPE_FIELDS (va_list_type_node);
    offset_field = TREE_CHAIN (base_field);
*************** alpha_gimplify_va_arg (tree *expr_p, tre
*** 6525,6536 ****
  
    /* Find the value.  Note that this will be a stable indirection, or
       a composite of stable indirections in the case of complex.  */
!   *expr_p = alpha_gimplify_va_arg_1 (type, base, offset, pre_p, post_p);
  
    /* Stuff the offset temporary back into its field.  */
    t = build (MODIFY_EXPR, void_type_node, offset_field,
  	     fold_convert (TREE_TYPE (offset_field), offset));
    gimplify_and_add (t, pre_p);
  }
  \f
  /* Builtins.  */
--- 6516,6529 ----
  
    /* Find the value.  Note that this will be a stable indirection, or
       a composite of stable indirections in the case of complex.  */
!   r = alpha_gimplify_va_arg_1 (type, base, offset, pre_p, post_p);
  
    /* Stuff the offset temporary back into its field.  */
    t = build (MODIFY_EXPR, void_type_node, offset_field,
  	     fold_convert (TREE_TYPE (offset_field), offset));
    gimplify_and_add (t, pre_p);
+ 
+   return r;
  }
  \f
  /* Builtins.  */
*** ./config/i386/i386.c.~1~	2004-06-09 15:26:36.000000000 -0400
--- ./config/i386/i386.c	2004-06-09 23:57:55.000000000 -0400
*************** static bool ix86_expand_carry_flag_compa
*** 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
  {
--- 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 tree ix86_gimplify_va_arg (tree, tree, tree *, tree *);
  
  struct ix86_address
  {
*************** ix86_va_arg (tree valist, tree type)
*** 3418,3428 ****
  
  /* 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;
--- 3418,3426 ----
  
  /* Lower VA_ARG_EXPR at gimplification time.  */
  
! tree
! ix86_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_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;
*************** ix86_gimplify_va_arg (tree *expr_p, tree
*** 3435,3444 ****
  
    /* 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);
--- 3433,3439 ----
  
    /* Only 64bit target needs something special.  */
    if (!TARGET_64BIT)
!     return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
  
    f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
    f_fpr = TREE_CHAIN (f_gpr);
*************** ix86_gimplify_va_arg (tree *expr_p, tree
*** 3595,3606 ****
  		  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);
--- 3590,3601 ----
  		  src_addr = int_addr;
  		  src_offset = REGNO (reg) * 8;
  		}
! 	      src_addr = fold_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 = fold_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);
*************** ix86_gimplify_va_arg (tree *expr_p, tree
*** 3661,3671 ****
      }
  
    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);
  }
  \f
  /* Return nonzero if OP is either a i387 or SSE fp register.  */
--- 3656,3666 ----
      }
  
    ptrtype = build_pointer_type (type);
!   addr = fold_convert (ptrtype, addr);
  
    if (indirect_p)
      addr = build_fold_indirect_ref (addr);
!   return build_fold_indirect_ref (addr);
  }
  \f
  /* Return nonzero if OP is either a i387 or SSE fp register.  */
*** ./config/ia64/ia64.c.~1~	2004-06-09 15:26:36.000000000 -0400
--- ./config/ia64/ia64.c	2004-06-09 23:57:29.000000000 -0400
*************** static void ia64_vms_init_libfuncs (void
*** 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 *);
  
  \f
  /* Table of valid machine attributes.  */
--- 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 tree ia64_gimplify_va_arg (tree, tree, tree *, tree *);
  
  \f
  /* Table of valid machine attributes.  */
*************** ia64_va_arg (tree valist, tree type)
*** 3993,4011 ****
    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
--- 3993,4007 ----
    return std_expand_builtin_va_arg (valist, type);
  }
  
! static tree
! ia64_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
  {
    /* Variable sized types are passed by reference.  */
    if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
      {
!       tree ptrtype = build_pointer_type (type);
!       tree addr = std_gimplify_va_arg_expr (valist, ptrtype, pre_p, post_p);
!       return build_fold_indirect_ref (addr);
      }
  
    /* Aggregate arguments with alignment larger than 8 bytes start at
*************** ia64_gimplify_va_arg (tree *expr_p, tree
*** 4023,4029 ****
        gimplify_and_add (t, pre_p);
      }
  
!   std_gimplify_va_arg_expr (expr_p, pre_p, post_p);
  }
  \f
  /* Return 1 if function return value returned in memory.  Return 0 if it is
--- 4019,4025 ----
        gimplify_and_add (t, pre_p);
      }
  
!   return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
  }
  \f
  /* Return 1 if function return value returned in memory.  Return 0 if it is
*** ./config/rs6000/rs6000.c.~1~	2004-06-09 15:26:36.000000000 -0400
--- ./config/rs6000/rs6000.c	2004-06-10 01:34:59.000000000 -0400
*************** static tree get_prev_label (tree functio
*** 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.  */
  
--- 440,446 ----
  #endif
  
  static tree rs6000_build_builtin_va_list (void);
! static tree rs6000_gimplify_va_arg (tree, tree, tree *, tree *);
  
  /* Hash table stuff for keeping track of TOC entries.  */
  
*************** rs6000_va_arg (tree valist, tree type)
*** 5292,5302 ****
    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;
--- 5292,5300 ----
    return addr_rtx;
  }
  
! tree
! rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_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;
*************** rs6000_gimplify_va_arg (tree *expr_p, tr
*** 5318,5327 ****
  		      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)
--- 5316,5322 ----
  		      build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
  	  t = build1 (NOP_EXPR, build_pointer_type (ptrtype), t);
  	  t = build_fold_indirect_ref (t);
! 	  return build_fold_indirect_ref (t);
  	}
        if (targetm.calls.split_complex_arg
  	  && TREE_CODE (type) == COMPLEX_TYPE)
*************** rs6000_gimplify_va_arg (tree *expr_p, tr
*** 5332,5383 ****
  
  	  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));
--- 5327,5350 ----
  
  	  if (elem_size < UNITS_PER_WORD)
  	    {
! 	      tree real_part, imag_part;
  	      tree post = NULL_TREE;
  
! 	      real_part = rs6000_gimplify_va_arg (valist, elem_type, pre_p,
! 						  &post);
! 	      /* Copy the value into a temporary, lest the formal temporary
! 		 be reused out from under us.  */
! 	      real_part = get_initialized_tmp_var (real_part, pre_p, &post);
  	      append_to_statement_list (post, pre_p);
  
! 	      imag_part = rs6000_gimplify_va_arg (valist, elem_type, pre_p,
! 						  post_p);
  
! 	      return build (COMPLEX_EXPR, type, real_part, imag_part);
  	    }
  	}
  
!       return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
      }
  
    f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
*************** rs6000_gimplify_va_arg (tree *expr_p, tr
*** 5520,5532 ****
  
    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.  */
--- 5487,5499 ----
  
    if (indirect_p)
      {
!       addr = fold_convert (build_pointer_type (ptrtype), addr);
        addr = build_fold_indirect_ref (addr);
      }
    else
!     addr = fold_convert (ptrtype, addr);
  
!   return build_fold_indirect_ref (addr);
  }
  
  /* Builtins.  */
*** ./config/sparc/sparc.c.~1~	2004-06-09 15:26:36.000000000 -0400
--- ./config/sparc/sparc.c	2004-06-10 00:14:50.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,188 ----
  static rtx sparc_struct_value_rtx (tree, int);
  static bool sparc_return_in_memory (tree, tree);
  static bool sparc_strict_argument_naming (CUMULATIVE_ARGS *);
+ static tree sparc_gimplify_va_arg (tree, tree, tree *, tree *);
  \f
  /* Option handling.  */
  
*************** enum processor_type sparc_cpu;
*** 289,294 ****
--- 291,299 ----
  #undef TARGET_STRICT_ARGUMENT_NAMING
  #define TARGET_STRICT_ARGUMENT_NAMING sparc_strict_argument_naming
  
+ #undef TARGET_GIMPLIFY_VA_ARG_EXPR
+ #define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  \f
  /* Validate and override various options, and do some machine dependent
*************** sparc_va_arg (tree valist, tree type)
*** 6041,6046 ****
--- 6046,6144 ----
  
    return addr_rtx;
  }
+ 
+ tree
+ sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_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 = fold_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 = build_fold_addr_expr (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);
+       addr = dest_addr;
+     }
+   else
+     addr = fold_convert (ptrtype, addr);
+ 
+   return build_fold_indirect_ref (addr);
+ }
  \f
  /* 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-06-09 15:26:36.000000000 -0400
--- ./doc/tm.texi	2004-06-10 01:29:00.000000000 -0400
*************** The default value of this hook is @code{
*** 3864,3869 ****
--- 3864,3882 ----
  false.
  @end deftypefn
  
+ @deftypefn {Target Hook} tree TARGET_GIMPLIFY_VA_ARG_EXPR (tree @var{valist}, tree @var{type}, tree *@var{pre_p}, tree *@var{post_p})
+ 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}.
+ 
+ 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 an expression of type @var{type}, 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-09 15:26:36.000000000 -0400
--- ./builtins.c	2004-06-10 11:41:41.000000000 -0400
*************** expand_builtin_va_arg (tree valist, tree
*** 4362,4385 ****
  
  /* 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.  */
  
--- 4362,4380 ----
  
  /* Like std_expand_builtin_va_arg, but gimplify instead of expanding.  */
  
! tree
! std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
  {
    tree addr, t, type_size = NULL;
    tree align, alignm1;
    tree rounded_size;
    HOST_WIDE_INT boundary;
  
    /* 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);
  
    /* va_list pointer is aligned to PARM_BOUNDARY.  If argument actually
       requires greater alignment, we must perform dynamic alignment.  */
  
*************** std_gimplify_va_arg_expr (tree *expr_p, 
*** 4432,4440 ****
  							    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))
      {
--- 4427,4432 ----
*************** std_gimplify_va_arg_expr (tree *expr_p, 
*** 4444,4449 ****
--- 4436,4444 ----
        gimplify_stmt (&t);
        append_to_statement_list (t, post_p);
      }
+ 
+   addr = fold_convert (build_pointer_type (type), addr);
+   return build_fold_indirect_ref (addr);
  }
  
  /* Return a dummy expression of type TYPE in order to keep going after an
*************** gimplify_va_arg_expr (tree *expr_p, tree
*** 4487,4494 ****
    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
--- 4482,4488 ----
    if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type))
      {
        error ("first argument to `va_arg' not of type `va_list'");
!       return GS_ERROR;
      }
  
    /* Generate a diagnostic for requesting data of a type that cannot
*************** gimplify_va_arg_expr (tree *expr_p, tree
*** 4526,4539 ****
      {
        /* 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;
      }
  }
--- 4520,4546 ----
      {
        /* Make it easier for the backends by protecting the valist argument
           from multiple evaluations.  */
!       if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
! 	{
! 	  /* For this case, the backends will be expecting a pointer to
! 	     TREE_TYPE (va_list_type_node), but it's possible we've
! 	     actually been given an array (an actual va_list_type_node).
! 	     So fix it.  */
! 	  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);
! 	    }
! 	  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.calls.gimplify_va_arg_expr)
  	/* Once most targets are converted this should abort.  */
  	return GS_ALL_DONE;
  
!       *expr_p = targetm.calls.gimplify_va_arg_expr (valist, type, pre_p, post_p);
        return GS_OK;
      }
  }
*** ./tree-gimple.h.~1~	2004-06-09 15:26:36.000000000 -0400
--- ./tree-gimple.h	2004-06-09 23:57:29.000000000 -0400
*************** tree alloc_stmt_list (void);
*** 123,129 ****
  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);
--- 123,129 ----
  void free_stmt_list (tree);
  tree force_labels_r (tree *, int *, void *);
  enum gimplify_status gimplify_va_arg_expr (tree *, tree *, tree *);
! tree std_gimplify_va_arg_expr (tree, tree, tree *, tree *);
  
  /* In tree-nested.c.  */
  extern void lower_nested_functions (tree);

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: followup PATCH: Gimplify VA_ARG_EXPR
  2004-06-10 17:54       ` followup " Jason Merrill
@ 2004-06-14  5:51         ` Jason Merrill
  0 siblings, 0 replies; 6+ messages in thread
From: Jason Merrill @ 2004-06-14  5:51 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 333 bytes --]

Graham pointed out that having the prototype in tree-gimple.h means that
targets which can use the generic va_arg support need to #include it.
Fixed thus.

Built i686-pc-linux-gnu, applied to trunk.

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

	* tree.h: Move std_gimplify_va_arg_expr protoype here.
	* tree-gimple.h: From here.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-patch, Size: 931 bytes --]

*** tree-gimple.h.~1~	2004-06-09 23:57:29.000000000 -0400
--- tree-gimple.h	2004-06-13 17:37:22.000000000 -0400
*************** tree alloc_stmt_list (void);
*** 123,129 ****
  void free_stmt_list (tree);
  tree force_labels_r (tree *, int *, void *);
  enum gimplify_status gimplify_va_arg_expr (tree *, tree *, tree *);
- tree std_gimplify_va_arg_expr (tree, tree, tree *, tree *);
  
  /* In tree-nested.c.  */
  extern void lower_nested_functions (tree);
--- 123,128 ----
*** tree.h.~1~	2004-06-13 17:33:54.000000000 -0400
--- tree.h	2004-06-13 17:37:37.000000000 -0400
*************** extern tree mathfn_built_in (tree, enum 
*** 3526,3531 ****
--- 3526,3532 ----
  extern tree strip_float_extensions (tree);
  extern tree simplify_builtin (tree, int);
  extern tree c_strlen (tree, int);
+ extern tree std_gimplify_va_arg_expr (tree, tree, tree *, tree *);
  
  /* In convert.c */
  extern tree strip_float_extensions (tree);

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2004-06-14  3:41 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-06-09  7:21 PATCH: Gimplify VA_ARG_EXPR Jason Merrill
2004-06-09 21:39 ` Richard Henderson
2004-06-09 22:01   ` Jason Merrill
2004-06-09 22:30     ` Richard Henderson
2004-06-10 17:54       ` followup " Jason Merrill
2004-06-14  5:51         ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).