public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* gimple va_arg for mips
@ 2004-07-09  4:27 Richard Henderson
  2004-07-09  8:18 ` Richard Sandiford
  0 siblings, 1 reply; 12+ messages in thread
From: Richard Henderson @ 2004-07-09  4:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: Eric Christopher, Richard Sandiford

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

Ouch.  So, like, the mips maintainers have a choice to make.

Patch 1 changes the ABI for !EABI such that variable sized types are
passed by reference.  With this, we're able to pass them through varargs.

The patch that was supposed to make that work,

2003-09-25  Richard Sandiford  <rsandifo@redhat.com>
                                                                                
        PR target/6222
        * config/mips/mips.c (mips_va_arg): Handle arguments that must be
        passed on the stack.

only works when va_arg is called from the same function that performed
the va_start.  I'm not certain that I can replicate this hackery at the
tree level, or if it's even desirable.

Patch 2 leaves the ABI alone, but generates a warning and __builtin_trap
if called for a variable sized argument.

In addition, there appears to have been an alignment and padding problem
with the old code.  It didn't follow the same padding as the caller side.
See PAD_VARARGS_DOWN.

Anyway, please pick one and give it a bit more testing than eyeballs.


r~

[-- Attachment #2: d-mips-1 --]
[-- Type: text/plain, Size: 19472 bytes --]

Index: mips-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips-protos.h,v
retrieving revision 1.71
diff -c -p -d -r1.71 mips-protos.h
*** mips-protos.h	7 Jul 2004 19:17:04 -0000	1.71
--- mips-protos.h	9 Jul 2004 02:24:15 -0000
*************** extern int function_arg_partial_nregs (c
*** 143,149 ****
  extern bool mips_pad_arg_upward (enum machine_mode, tree);
  extern bool mips_pad_reg_upward (enum machine_mode, tree);
  extern void mips_va_start (tree, rtx);
- extern struct rtx_def *mips_va_arg (tree, tree);
  
  extern bool mips_expand_unaligned_load (rtx, rtx, unsigned int, int);
  extern bool mips_expand_unaligned_store (rtx, rtx, unsigned int, int);
--- 143,148 ----
Index: mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.426
diff -c -p -d -r1.426 mips.c
*** mips.c	7 Jul 2004 19:24:28 -0000	1.426
--- mips.c	9 Jul 2004 02:24:16 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 55,60 ****
--- 55,61 ----
  #include "langhooks.h"
  #include "cfglayout.h"
  #include "sched-int.h"
+ #include "tree-gimple.h"
  
  /* Enumeration for all of the relational tests, so that we can build
     arrays indexed by the test type, and not worry about the order
*************** static void mips_init_libfuncs (void);
*** 289,294 ****
--- 290,296 ----
  static void mips_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
  					 tree, int *, int);
  static tree mips_build_builtin_va_list (void);
+ static tree mips_gimplify_va_arg_expr (tree, tree, tree *, tree *);
  
  #if TARGET_IRIX
  static void irix_asm_named_section_1 (const char *, unsigned int,
*************** const struct mips_cpu_info mips_cpu_info
*** 775,780 ****
--- 777,784 ----
  
  #undef TARGET_BUILD_BUILTIN_VA_LIST
  #define TARGET_BUILD_BUILTIN_VA_LIST mips_build_builtin_va_list
+ #undef TARGET_GIMPLIFY_VA_ARG_EXPR
+ #define TARGET_GIMPLIFY_VA_ARG_EXPR mips_gimplify_va_arg_expr
  
  #undef TARGET_PROMOTE_FUNCTION_ARGS
  #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
*************** mips_va_start (tree valist, rtx nextarg)
*** 4098,4369 ****
  \f
  /* Implement va_arg.  */
  
! rtx
! mips_va_arg (tree valist, tree type)
  {
    HOST_WIDE_INT size, rsize;
!   rtx addr_rtx;
!   tree t;
  
    size = int_size_in_bytes (type);
    rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
  
!   if (mips_abi == ABI_EABI)
      {
!       bool indirect;
!       rtx r;
! 
!       indirect
! 	= function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0);
! 
!       if (indirect)
! 	{
! 	  size = POINTER_SIZE / BITS_PER_UNIT;
! 	  rsize = UNITS_PER_WORD;
! 	}
! 
!       if (!EABI_FLOAT_VARARGS_P)
! 	{
! 	  /* Case of all args in a merged stack.  No need to check bounds,
! 	     just advance valist along the stack.  */
! 
! 	  tree gpr = valist;
! 	  if (!indirect
! 	      && !TARGET_64BIT
! 	      && TYPE_ALIGN (type) > (unsigned) BITS_PER_WORD)
! 	    {
! 	      /* Align the pointer using: ap = (ap + align - 1) & -align,
! 		 where align is 2 * UNITS_PER_WORD.  */
! 	      t = build (PLUS_EXPR, TREE_TYPE (gpr), gpr,
! 			 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 (gpr), gpr, t);
! 	      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 	    }
! 
! 	  /* Emit code to set addr_rtx to the valist, and postincrement
! 	     the valist by the size of the argument, rounded up to the
! 	     next word.	 Account for padding on big-endian targets.  */
! 	  t = build (POSTINCREMENT_EXPR, TREE_TYPE (gpr), gpr,
! 		     size_int (rsize));
! 	  addr_rtx = expand_expr (t, 0, Pmode, EXPAND_NORMAL);
! 	  if (BYTES_BIG_ENDIAN)
! 	    addr_rtx = plus_constant (addr_rtx, rsize - size);
! 
! 	  /* Flush the POSTINCREMENT.  */
! 	  emit_queue();
! 	}
!       else
! 	{
! 	  /* Not a simple merged stack.	 */
! 
! 	  tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
! 	  tree ovfl, top, off;
! 	  rtx lab_over = NULL_RTX, lab_false;
! 	  HOST_WIDE_INT osize;
  
! 	  addr_rtx = gen_reg_rtx (Pmode);
  
! 	  f_ovfl = TYPE_FIELDS (va_list_type_node);
! 	  f_gtop = TREE_CHAIN (f_ovfl);
! 	  f_ftop = TREE_CHAIN (f_gtop);
! 	  f_goff = TREE_CHAIN (f_ftop);
! 	  f_foff = TREE_CHAIN (f_goff);
  
! 	  /* We maintain separate pointers and offsets for floating-point
! 	     and integer arguments, but we need similar code in both cases.
! 	     Let:
  
! 		 TOP be the top of the register save area;
! 		 OFF be the offset from TOP of the next register;
! 		 ADDR_RTX be the address of the argument;
! 		 RSIZE be the number of bytes used to store the argument
! 		   when it's in the register save area;
! 		 OSIZE be the number of bytes used to store it when it's
! 		   in the stack overflow area; and
! 		 PADDING be (BYTES_BIG_ENDIAN ? OSIZE - RSIZE : 0)
  
! 	     The code we want is:
  
! 		  1: off &= -rsize;	  // round down
! 		  2: if (off != 0)
! 		  3:   {
! 		  4:	 addr_rtx = top - off;
! 		  5:	 off -= rsize;
! 		  6:   }
! 		  7: else
! 		  8:   {
! 		  9:	 ovfl += ((intptr_t) ovfl + osize - 1) & -osize;
! 		 10:	 addr_rtx = ovfl + PADDING;
! 		 11:	 ovfl += osize;
! 		 14:   }
  
! 	     [1] and [9] can sometimes be optimized away.  */
  
! 	  lab_false = gen_label_rtx ();
! 	  lab_over = gen_label_rtx ();
  
! 	  ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
! 			NULL_TREE);
! 	  if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
! 	      && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FPVALUE)
! 	    {
! 	      top = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
! 			   NULL_TREE);
! 	      off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
! 			   NULL_TREE);
  
! 	      /* When floating-point registers are saved to the stack,
! 		 each one will take up UNITS_PER_HWFPVALUE bytes, regardless
! 		 of the float's precision.  */
! 	      rsize = UNITS_PER_HWFPVALUE;
  
! 	      /* Overflow arguments are padded to UNITS_PER_WORD bytes
! 		 (= PARM_BOUNDARY bits).  This can be different from RSIZE
! 		 in two cases:
  
! 		     (1) On 32-bit targets when TYPE is a structure such as:
  
! 			     struct s { float f; };
  
! 			 Such structures are passed in paired FPRs, so RSIZE
! 			 will be 8 bytes.  However, the structure only takes
! 			 up 4 bytes of memory, so OSIZE will only be 4.
  
! 		     (2) In combinations such as -mgp64 -msingle-float
! 			 -fshort-double.  Doubles passed in registers
! 			 will then take up 4 (UNITS_PER_HWFPVALUE) bytes,
! 			 but those passed on the stack take up
! 			 UNITS_PER_WORD bytes.  */
! 	      osize = MAX (GET_MODE_SIZE (TYPE_MODE (type)), UNITS_PER_WORD);
! 	    }
! 	  else
  	    {
! 	      top = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
! 			   NULL_TREE);
! 	      off = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
! 			   NULL_TREE);
! 	      if (rsize > UNITS_PER_WORD)
! 		{
! 		  /* [1] Emit code for: off &= -rsize.	*/
! 		  t = build (BIT_AND_EXPR, TREE_TYPE (off), off,
! 			     build_int_2 (-rsize, -1));
! 		  t = build (MODIFY_EXPR, TREE_TYPE (off), off, t);
! 		  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 		}
! 	      osize = rsize;
  	    }
  
! 	  /* [2] Emit code to branch if off == 0.  */
! 	  r = expand_expr (off, NULL_RTX, TYPE_MODE (TREE_TYPE (off)),
! 			   EXPAND_NORMAL);
! 	  emit_cmp_and_jump_insns (r, const0_rtx, EQ, const1_rtx, GET_MODE (r),
! 				   1, lab_false);
! 
! 	  /* [4] Emit code for: addr_rtx = top - off.  On big endian machines,
! 	     the argument has RSIZE - SIZE bytes of leading padding.  */
! 	  t = build (MINUS_EXPR, TREE_TYPE (top), top, off);
! 	  if (BYTES_BIG_ENDIAN && rsize > size)
! 	    t = build (PLUS_EXPR, TREE_TYPE (t), t,
! 		       build_int_2 (rsize - size, 0));
! 	  r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
! 	  if (r != addr_rtx)
! 	    emit_move_insn (addr_rtx, r);
! 
! 	  /* [5] Emit code for: off -= rsize.  */
! 	  t = build (MINUS_EXPR, TREE_TYPE (off), off, build_int_2 (rsize, 0));
! 	  t = build (MODIFY_EXPR, TREE_TYPE (off), off, t);
! 	  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 
! 	  /* [7] Emit code to jump over the else clause, then the label
! 	     that starts it.  */
! 	  emit_queue();
! 	  emit_jump (lab_over);
! 	  emit_barrier ();
! 	  emit_label (lab_false);
! 
! 	  if (osize > UNITS_PER_WORD)
! 	    {
! 	      /* [9] Emit: ovfl += ((intptr_t) ovfl + osize - 1) & -osize.  */
! 	      t = build (PLUS_EXPR, TREE_TYPE (ovfl), ovfl,
! 			 build_int_2 (osize - 1, 0));
! 	      t = build (BIT_AND_EXPR, TREE_TYPE (ovfl), t,
! 			 build_int_2 (-osize, -1));
! 	      t = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
! 	      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 	    }
  
! 	  /* [10, 11].	Emit code to store ovfl in addr_rtx, then
! 	     post-increment ovfl by osize.  On big-endian machines,
! 	     the argument has OSIZE - SIZE bytes of leading padding.  */
! 	  t = build (POSTINCREMENT_EXPR, TREE_TYPE (ovfl), ovfl,
! 		     size_int (osize));
! 	  if (BYTES_BIG_ENDIAN && osize > size)
! 	    t = build (PLUS_EXPR, TREE_TYPE (t), t,
! 		       build_int_2 (osize - size, 0));
! 	  r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
! 	  if (r != addr_rtx)
! 	    emit_move_insn (addr_rtx, r);
  
! 	  emit_queue();
! 	  emit_label (lab_over);
! 	}
!       if (indirect)
  	{
! 	  addr_rtx = force_reg (Pmode, addr_rtx);
! 	  r = gen_rtx_MEM (Pmode, addr_rtx);
! 	  set_mem_alias_set (r, get_varargs_alias_set ());
! 	  emit_move_insn (addr_rtx, r);
  	}
!       return addr_rtx;
!     }
!   else
!     {
!       /* Not EABI.  */
!       int align;
!       HOST_WIDE_INT min_offset;
! 
!       /* ??? The original va-mips.h did always align, despite the fact
! 	 that alignments <= UNITS_PER_WORD are preserved by the va_arg
! 	 increment mechanism.  */
  
!       if (TARGET_NEWABI && TYPE_ALIGN (type) > 64)
! 	align = 16;
!       else if (TARGET_64BIT)
! 	align = 8;
!       else if (TYPE_ALIGN (type) > 32)
! 	align = 8;
        else
! 	align = 4;
  
!       t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
! 		 build_int_2 (align - 1, 0));
!       t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
  
!       /* If arguments of type TYPE must be passed on the stack,
! 	 set MIN_OFFSET to the offset of the first stack parameter.  */
!       if (!MUST_PASS_IN_STACK (TYPE_MODE (type), type))
! 	min_offset = 0;
!       else if (TARGET_NEWABI)
! 	min_offset = current_function_pretend_args_size;
!       else
! 	min_offset = REG_PARM_STACK_SPACE (current_function_decl);
  
!       /* Make sure the new address is at least MIN_OFFSET bytes from
! 	 the incoming argument pointer.  */
!       if (min_offset > 0)
! 	t = build (MAX_EXPR, TREE_TYPE (valist), t,
! 		   make_tree (TREE_TYPE (valist),
! 			      plus_constant (virtual_incoming_args_rtx,
! 					     min_offset)));
  
!       t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
!       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
  
!       /* Everything past the alignment is standard.  */
!       return std_expand_builtin_va_arg (valist, type);
!     }
  }
  \f
  /* Return true if it is possible to use left/right accesses for a
--- 4102,4280 ----
  \f
  /* Implement va_arg.  */
  
! static tree
! mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
  {
    HOST_WIDE_INT size, rsize;
!   tree addr;
!   bool indirect;
! 
!   indirect
!     = function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0);
! 
!   if (indirect)
!     type = build_pointer_type (type);
  
    size = int_size_in_bytes (type);
    rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
  
!   if (mips_abi != ABI_EABI || !EABI_FLOAT_VARARGS_P)
!     addr = std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
!   else
      {
!       /* Not a simple merged stack.	 */
  
!       tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
!       tree ovfl, top, off, align;
!       HOST_WIDE_INT osize;
!       tree t, u;
  
!       f_ovfl = TYPE_FIELDS (va_list_type_node);
!       f_gtop = TREE_CHAIN (f_ovfl);
!       f_ftop = TREE_CHAIN (f_gtop);
!       f_goff = TREE_CHAIN (f_ftop);
!       f_foff = TREE_CHAIN (f_goff);
  
!       /* We maintain separate pointers and offsets for floating-point
! 	 and integer arguments, but we need similar code in both cases.
! 	 Let:
  
! 	 TOP be the top of the register save area;
! 	 OFF be the offset from TOP of the next register;
! 	 ADDR_RTX be the address of the argument;
! 	 RSIZE be the number of bytes used to store the argument
! 	 when it's in the register save area;
! 	 OSIZE be the number of bytes used to store it when it's
! 	 in the stack overflow area; and
! 	 PADDING be (BYTES_BIG_ENDIAN ? OSIZE - RSIZE : 0)
  
! 	 The code we want is:
  
! 	 1: off &= -rsize;	  // round down
! 	 2: if (off != 0)
! 	 3:   {
! 	 4:	 addr_rtx = top - off;
! 	 5:	 off -= rsize;
! 	 6:   }
! 	 7: else
! 	 8:   {
! 	 9:	 ovfl += ((intptr_t) ovfl + osize - 1) & -osize;
! 	 10:	 addr_rtx = ovfl + PADDING;
! 	 11:	 ovfl += osize;
! 	 14:   }
  
! 	 [1] and [9] can sometimes be optimized away.  */
  
!       ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
! 		    NULL_TREE);
  
!       if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
! 	  && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FPVALUE)
! 	{
! 	  top = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
! 		       NULL_TREE);
! 	  off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
! 		       NULL_TREE);
  
! 	  /* When floating-point registers are saved to the stack,
! 	     each one will take up UNITS_PER_HWFPVALUE bytes, regardless
! 	     of the float's precision.  */
! 	  rsize = UNITS_PER_HWFPVALUE;
  
! 	  /* Overflow arguments are padded to UNITS_PER_WORD bytes
! 	     (= PARM_BOUNDARY bits).  This can be different from RSIZE
! 	     in two cases:
  
! 	     (1) On 32-bit targets when TYPE is a structure such as:
  
! 	     struct s { float f; };
  
! 	     Such structures are passed in paired FPRs, so RSIZE
! 	     will be 8 bytes.  However, the structure only takes
! 	     up 4 bytes of memory, so OSIZE will only be 4.
  
! 	     (2) In combinations such as -mgp64 -msingle-float
! 	     -fshort-double.  Doubles passed in registers
! 	     will then take up 4 (UNITS_PER_HWFPVALUE) bytes,
! 	     but those passed on the stack take up
! 	     UNITS_PER_WORD bytes.  */
! 	  osize = MAX (GET_MODE_SIZE (TYPE_MODE (type)), UNITS_PER_WORD);
! 	}
!       else
! 	{
! 	  top = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
! 		       NULL_TREE);
! 	  off = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
! 		       NULL_TREE);
! 	  if (rsize > UNITS_PER_WORD)
  	    {
! 	      /* [1] Emit code for: off &= -rsize.	*/
! 	      t = build (BIT_AND_EXPR, TREE_TYPE (off), off,
! 			 build_int_2 (-rsize, -1));
! 	      t = build (MODIFY_EXPR, TREE_TYPE (off), off, t);
! 	      gimplify_and_add (t, pre_p);
  	    }
+ 	  osize = rsize;
+ 	}
  
!       /* [2] Emit code to branch if off == 0.  */
!       t = lang_hooks.truthvalue_conversion (off);
!       addr = build (COND_EXPR, ptr_type_node, t, NULL, NULL);
  
!       /* [5] Emit code for: off -= rsize.  We do this as a form of
! 	 post-increment not available to C.  Also widen for the 
! 	 coming pointer arithmetic.  */
!       t = fold_convert (TREE_TYPE (off), build_int_2 (rsize, 0));
!       t = build (POSTDECREMENT_EXPR, TREE_TYPE (off), off, t);
!       t = fold_convert (sizetype, t);
!       t = fold_convert (TREE_TYPE (top), t);
  
!       /* [4] Emit code for: addr_rtx = top - off.  On big endian machines,
! 	 the argument has RSIZE - SIZE bytes of leading padding.  */
!       t = build (MINUS_EXPR, TREE_TYPE (top), top, t);
!       if (BYTES_BIG_ENDIAN && rsize > size)
  	{
! 	  u = fold_convert (TREE_TYPE (t), build_int_2 (rsize - size, 0));
! 	  t = build (PLUS_EXPR, TREE_TYPE (t), t, u);
  	}
!       COND_EXPR_THEN (addr) = t;
  
!       if (osize > UNITS_PER_WORD)
! 	{
! 	  /* [9] Emit: ovfl += ((intptr_t) ovfl + osize - 1) & -osize.  */
! 	  u = fold_convert (TREE_TYPE (ovfl), build_int_2 (osize - 1, 0));
! 	  t = build (PLUS_EXPR, TREE_TYPE (ovfl), ovfl, u);
! 	  u = fold_convert (TREE_TYPE (ovfl), build_int_2 (-osize, -1));
! 	  t = build (BIT_AND_EXPR, TREE_TYPE (ovfl), t, u);
! 	  align = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
! 	}
        else
! 	align = NULL;
  
!       /* [10, 11].	Emit code to store ovfl in addr_rtx, then
! 	 post-increment ovfl by osize.  On big-endian machines,
! 	 the argument has OSIZE - SIZE bytes of leading padding.  */
!       u = fold_convert (TREE_TYPE (ovfl), build_int_2 (osize, 0));
!       t = build (POSTINCREMENT_EXPR, TREE_TYPE (ovfl), ovfl, u);
!       if (BYTES_BIG_ENDIAN && osize > size)
! 	{
! 	  u = fold_convert (TREE_TYPE (t), build_int_2 (osize - size, 0));
! 	  t = build (PLUS_EXPR, TREE_TYPE (t), t, u);
! 	}
  
!       /* String [9] and [10,11] together.  */
!       if (align)
! 	t = build (COMPOUND_EXPR, TREE_TYPE (t), align, t);
!       COND_EXPR_ELSE (addr) = t;
  
!       addr = fold_convert (build_pointer_type (type), addr);
!       addr = build_fold_indirect_ref (addr);
!     }
  
!   if (indirect)
!     addr = build_fold_indirect_ref (addr);
  
!   return addr;
  }
  \f
  /* Return true if it is possible to use left/right accesses for a
*************** function_arg_pass_by_reference (const CU
*** 7490,7507 ****
  				enum machine_mode mode, tree type,
  				int named ATTRIBUTE_UNUSED)
  {
!   int size;
! 
!   /* The EABI is the only one to pass args by reference.  */
!   if (mips_abi != ABI_EABI)
!     return 0;
  
!   /* ??? How should SCmode be handled?  */
!   if (type == NULL_TREE || mode == DImode || mode == DFmode)
!     return 0;
  
!   size = int_size_in_bytes (type);
!   return size == -1 || size > UNITS_PER_WORD;
  }
  
  /* Return the class of registers for which a mode change from FROM to TO
--- 7401,7422 ----
  				enum machine_mode mode, tree type,
  				int named ATTRIBUTE_UNUSED)
  {
!   if (mips_abi == ABI_EABI)
!     {
!       int size;
  
!       /* ??? How should SCmode be handled?  */
!       if (type == NULL_TREE || mode == DImode || mode == DFmode)
! 	return 0;
  
!       size = int_size_in_bytes (type);
!       return size == -1 || size > UNITS_PER_WORD;
!     }
!   else
!     {
!       /* If we have a variable-sized parameter, we have no choice.  */
!       return MUST_PASS_IN_STACK (mode, type);
!     }
  }
  
  /* Return the class of registers for which a mode change from FROM to TO
Index: mips.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.h,v
retrieving revision 1.347
diff -c -p -d -r1.347 mips.h
*** mips.h	7 Jul 2004 19:17:05 -0000	1.347
--- mips.h	9 Jul 2004 02:24:16 -0000
*************** typedef struct mips_args {
*** 2403,2412 ****
  /* Implement `va_start' for varargs and stdarg.  */
  #define EXPAND_BUILTIN_VA_START(valist, nextarg) \
    mips_va_start (valist, nextarg)
- 
- /* Implement `va_arg'.  */
- #define EXPAND_BUILTIN_VA_ARG(valist, type) \
-   mips_va_arg (valist, type)
  \f
  /* Output assembler code to FILE to increment profiler label # LABELNO
     for profiling a function entry.  */
--- 2403,2408 ----

[-- Attachment #3: d-mips-2 --]
[-- Type: text/plain, Size: 19289 bytes --]

? z
Index: mips-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips-protos.h,v
retrieving revision 1.71
diff -c -p -d -r1.71 mips-protos.h
*** mips-protos.h	7 Jul 2004 19:17:04 -0000	1.71
--- mips-protos.h	9 Jul 2004 02:46:00 -0000
*************** extern int function_arg_partial_nregs (c
*** 143,149 ****
  extern bool mips_pad_arg_upward (enum machine_mode, tree);
  extern bool mips_pad_reg_upward (enum machine_mode, tree);
  extern void mips_va_start (tree, rtx);
- extern struct rtx_def *mips_va_arg (tree, tree);
  
  extern bool mips_expand_unaligned_load (rtx, rtx, unsigned int, int);
  extern bool mips_expand_unaligned_store (rtx, rtx, unsigned int, int);
--- 143,148 ----
Index: mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.426
diff -c -p -d -r1.426 mips.c
*** mips.c	7 Jul 2004 19:24:28 -0000	1.426
--- mips.c	9 Jul 2004 02:46:00 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 55,60 ****
--- 55,61 ----
  #include "langhooks.h"
  #include "cfglayout.h"
  #include "sched-int.h"
+ #include "tree-gimple.h"
  
  /* Enumeration for all of the relational tests, so that we can build
     arrays indexed by the test type, and not worry about the order
*************** static void mips_init_libfuncs (void);
*** 289,294 ****
--- 290,296 ----
  static void mips_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
  					 tree, int *, int);
  static tree mips_build_builtin_va_list (void);
+ static tree mips_gimplify_va_arg_expr (tree, tree, tree *, tree *);
  
  #if TARGET_IRIX
  static void irix_asm_named_section_1 (const char *, unsigned int,
*************** const struct mips_cpu_info mips_cpu_info
*** 775,780 ****
--- 777,784 ----
  
  #undef TARGET_BUILD_BUILTIN_VA_LIST
  #define TARGET_BUILD_BUILTIN_VA_LIST mips_build_builtin_va_list
+ #undef TARGET_GIMPLIFY_VA_ARG_EXPR
+ #define TARGET_GIMPLIFY_VA_ARG_EXPR mips_gimplify_va_arg_expr
  
  #undef TARGET_PROMOTE_FUNCTION_ARGS
  #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
*************** mips_va_start (tree valist, rtx nextarg)
*** 4098,4369 ****
  \f
  /* Implement va_arg.  */
  
! rtx
! mips_va_arg (tree valist, tree type)
  {
    HOST_WIDE_INT size, rsize;
!   rtx addr_rtx;
!   tree t;
  
    size = int_size_in_bytes (type);
    rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
  
!   if (mips_abi == ABI_EABI)
      {
!       bool indirect;
!       rtx r;
! 
!       indirect
! 	= function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0);
! 
!       if (indirect)
! 	{
! 	  size = POINTER_SIZE / BITS_PER_UNIT;
! 	  rsize = UNITS_PER_WORD;
! 	}
! 
!       if (!EABI_FLOAT_VARARGS_P)
  	{
! 	  /* Case of all args in a merged stack.  No need to check bounds,
! 	     just advance valist along the stack.  */
! 
! 	  tree gpr = valist;
! 	  if (!indirect
! 	      && !TARGET_64BIT
! 	      && TYPE_ALIGN (type) > (unsigned) BITS_PER_WORD)
! 	    {
! 	      /* Align the pointer using: ap = (ap + align - 1) & -align,
! 		 where align is 2 * UNITS_PER_WORD.  */
! 	      t = build (PLUS_EXPR, TREE_TYPE (gpr), gpr,
! 			 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 (gpr), gpr, t);
! 	      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 	    }
  
! 	  /* Emit code to set addr_rtx to the valist, and postincrement
! 	     the valist by the size of the argument, rounded up to the
! 	     next word.	 Account for padding on big-endian targets.  */
! 	  t = build (POSTINCREMENT_EXPR, TREE_TYPE (gpr), gpr,
! 		     size_int (rsize));
! 	  addr_rtx = expand_expr (t, 0, Pmode, EXPAND_NORMAL);
! 	  if (BYTES_BIG_ENDIAN)
! 	    addr_rtx = plus_constant (addr_rtx, rsize - size);
  
! 	  /* Flush the POSTINCREMENT.  */
! 	  emit_queue();
  	}
-       else
- 	{
- 	  /* Not a simple merged stack.	 */
  
! 	  tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
! 	  tree ovfl, top, off;
! 	  rtx lab_over = NULL_RTX, lab_false;
! 	  HOST_WIDE_INT osize;
  
! 	  addr_rtx = gen_reg_rtx (Pmode);
  
! 	  f_ovfl = TYPE_FIELDS (va_list_type_node);
! 	  f_gtop = TREE_CHAIN (f_ovfl);
! 	  f_ftop = TREE_CHAIN (f_gtop);
! 	  f_goff = TREE_CHAIN (f_ftop);
! 	  f_foff = TREE_CHAIN (f_goff);
  
! 	  /* We maintain separate pointers and offsets for floating-point
! 	     and integer arguments, but we need similar code in both cases.
! 	     Let:
  
! 		 TOP be the top of the register save area;
! 		 OFF be the offset from TOP of the next register;
! 		 ADDR_RTX be the address of the argument;
! 		 RSIZE be the number of bytes used to store the argument
! 		   when it's in the register save area;
! 		 OSIZE be the number of bytes used to store it when it's
! 		   in the stack overflow area; and
! 		 PADDING be (BYTES_BIG_ENDIAN ? OSIZE - RSIZE : 0)
  
! 	     The code we want is:
  
! 		  1: off &= -rsize;	  // round down
! 		  2: if (off != 0)
! 		  3:   {
! 		  4:	 addr_rtx = top - off;
! 		  5:	 off -= rsize;
! 		  6:   }
! 		  7: else
! 		  8:   {
! 		  9:	 ovfl += ((intptr_t) ovfl + osize - 1) & -osize;
! 		 10:	 addr_rtx = ovfl + PADDING;
! 		 11:	 ovfl += osize;
! 		 14:   }
  
! 	     [1] and [9] can sometimes be optimized away.  */
  
! 	  lab_false = gen_label_rtx ();
! 	  lab_over = gen_label_rtx ();
  
! 	  ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
! 			NULL_TREE);
! 	  if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
! 	      && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FPVALUE)
! 	    {
! 	      top = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
! 			   NULL_TREE);
! 	      off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
! 			   NULL_TREE);
  
! 	      /* When floating-point registers are saved to the stack,
! 		 each one will take up UNITS_PER_HWFPVALUE bytes, regardless
! 		 of the float's precision.  */
! 	      rsize = UNITS_PER_HWFPVALUE;
  
! 	      /* Overflow arguments are padded to UNITS_PER_WORD bytes
! 		 (= PARM_BOUNDARY bits).  This can be different from RSIZE
! 		 in two cases:
  
! 		     (1) On 32-bit targets when TYPE is a structure such as:
  
! 			     struct s { float f; };
  
! 			 Such structures are passed in paired FPRs, so RSIZE
! 			 will be 8 bytes.  However, the structure only takes
! 			 up 4 bytes of memory, so OSIZE will only be 4.
  
! 		     (2) In combinations such as -mgp64 -msingle-float
! 			 -fshort-double.  Doubles passed in registers
! 			 will then take up 4 (UNITS_PER_HWFPVALUE) bytes,
! 			 but those passed on the stack take up
! 			 UNITS_PER_WORD bytes.  */
! 	      osize = MAX (GET_MODE_SIZE (TYPE_MODE (type)), UNITS_PER_WORD);
! 	    }
! 	  else
  	    {
! 	      top = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
! 			   NULL_TREE);
! 	      off = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
! 			   NULL_TREE);
! 	      if (rsize > UNITS_PER_WORD)
! 		{
! 		  /* [1] Emit code for: off &= -rsize.	*/
! 		  t = build (BIT_AND_EXPR, TREE_TYPE (off), off,
! 			     build_int_2 (-rsize, -1));
! 		  t = build (MODIFY_EXPR, TREE_TYPE (off), off, t);
! 		  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 		}
! 	      osize = rsize;
  	    }
  
! 	  /* [2] Emit code to branch if off == 0.  */
! 	  r = expand_expr (off, NULL_RTX, TYPE_MODE (TREE_TYPE (off)),
! 			   EXPAND_NORMAL);
! 	  emit_cmp_and_jump_insns (r, const0_rtx, EQ, const1_rtx, GET_MODE (r),
! 				   1, lab_false);
! 
! 	  /* [4] Emit code for: addr_rtx = top - off.  On big endian machines,
! 	     the argument has RSIZE - SIZE bytes of leading padding.  */
! 	  t = build (MINUS_EXPR, TREE_TYPE (top), top, off);
! 	  if (BYTES_BIG_ENDIAN && rsize > size)
! 	    t = build (PLUS_EXPR, TREE_TYPE (t), t,
! 		       build_int_2 (rsize - size, 0));
! 	  r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
! 	  if (r != addr_rtx)
! 	    emit_move_insn (addr_rtx, r);
! 
! 	  /* [5] Emit code for: off -= rsize.  */
! 	  t = build (MINUS_EXPR, TREE_TYPE (off), off, build_int_2 (rsize, 0));
! 	  t = build (MODIFY_EXPR, TREE_TYPE (off), off, t);
! 	  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 
! 	  /* [7] Emit code to jump over the else clause, then the label
! 	     that starts it.  */
! 	  emit_queue();
! 	  emit_jump (lab_over);
! 	  emit_barrier ();
! 	  emit_label (lab_false);
! 
! 	  if (osize > UNITS_PER_WORD)
! 	    {
! 	      /* [9] Emit: ovfl += ((intptr_t) ovfl + osize - 1) & -osize.  */
! 	      t = build (PLUS_EXPR, TREE_TYPE (ovfl), ovfl,
! 			 build_int_2 (osize - 1, 0));
! 	      t = build (BIT_AND_EXPR, TREE_TYPE (ovfl), t,
! 			 build_int_2 (-osize, -1));
! 	      t = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
! 	      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 	    }
  
! 	  /* [10, 11].	Emit code to store ovfl in addr_rtx, then
! 	     post-increment ovfl by osize.  On big-endian machines,
! 	     the argument has OSIZE - SIZE bytes of leading padding.  */
! 	  t = build (POSTINCREMENT_EXPR, TREE_TYPE (ovfl), ovfl,
! 		     size_int (osize));
! 	  if (BYTES_BIG_ENDIAN && osize > size)
! 	    t = build (PLUS_EXPR, TREE_TYPE (t), t,
! 		       build_int_2 (osize - size, 0));
! 	  r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
! 	  if (r != addr_rtx)
! 	    emit_move_insn (addr_rtx, r);
  
! 	  emit_queue();
! 	  emit_label (lab_over);
! 	}
!       if (indirect)
  	{
! 	  addr_rtx = force_reg (Pmode, addr_rtx);
! 	  r = gen_rtx_MEM (Pmode, addr_rtx);
! 	  set_mem_alias_set (r, get_varargs_alias_set ());
! 	  emit_move_insn (addr_rtx, r);
  	}
!       return addr_rtx;
!     }
!   else
!     {
!       /* Not EABI.  */
!       int align;
!       HOST_WIDE_INT min_offset;
! 
!       /* ??? The original va-mips.h did always align, despite the fact
! 	 that alignments <= UNITS_PER_WORD are preserved by the va_arg
! 	 increment mechanism.  */
  
!       if (TARGET_NEWABI && TYPE_ALIGN (type) > 64)
! 	align = 16;
!       else if (TARGET_64BIT)
! 	align = 8;
!       else if (TYPE_ALIGN (type) > 32)
! 	align = 8;
        else
! 	align = 4;
  
!       t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
! 		 build_int_2 (align - 1, 0));
!       t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
  
!       /* If arguments of type TYPE must be passed on the stack,
! 	 set MIN_OFFSET to the offset of the first stack parameter.  */
!       if (!MUST_PASS_IN_STACK (TYPE_MODE (type), type))
! 	min_offset = 0;
!       else if (TARGET_NEWABI)
! 	min_offset = current_function_pretend_args_size;
!       else
! 	min_offset = REG_PARM_STACK_SPACE (current_function_decl);
  
!       /* Make sure the new address is at least MIN_OFFSET bytes from
! 	 the incoming argument pointer.  */
!       if (min_offset > 0)
! 	t = build (MAX_EXPR, TREE_TYPE (valist), t,
! 		   make_tree (TREE_TYPE (valist),
! 			      plus_constant (virtual_incoming_args_rtx,
! 					     min_offset)));
  
!       t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
!       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
  
!       /* Everything past the alignment is standard.  */
!       return std_expand_builtin_va_arg (valist, type);
!     }
  }
  \f
  /* Return true if it is possible to use left/right accesses for a
--- 4102,4306 ----
  \f
  /* Implement va_arg.  */
  
! static tree
! mips_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
  {
    HOST_WIDE_INT size, rsize;
!   tree addr;
!   bool indirect;
!   tree t, u;
! 
!   indirect
!     = function_arg_pass_by_reference (NULL, TYPE_MODE (type), type, 0);
! 
!   if (indirect)
!     type = build_pointer_type (type);
  
    size = int_size_in_bytes (type);
    rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
  
!   if (mips_abi != ABI_EABI)
      {
!       /* If this type must be passed in the stack, that means we should
! 	 have skipped all of the remaining saved registers.  Except that
! 	 we have no information at all about how many have been used,
! 	 and how many remain.  A previous implementation tried to do
! 	 something with current_function_pretend_args_size and
! 	 virtual_incoming_args_rtx, but that only works if the va_list
! 	 is being in the same function for which it was va_start'd.  */
!       if (MUST_PASS_IN_STACK (TYPE_MODE (type), type))
  	{
! 	  warning ("this ABI does not support passing variable sized "
! 		   "types through %<...%>");
  
! 	  t = implicit_built_in_decls[BUILT_IN_TRAP];
! 	  t = build_function_call_expr (t, NULL);
! 	  gimplify_and_add (t, pre_p);
  
! 	  addr = size_zero_node;
! 	  addr = fold_convert (build_pointer_type (type), addr);
! 	  addr = build_fold_indirect_ref (addr);
! 	  return addr;
  	}
  
!       addr = std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
!     }
!   else if (!EABI_FLOAT_VARARGS_P)
!     addr = std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
!   else
!     {
!       /* Not a simple merged stack.  */
  
!       tree f_ovfl, f_gtop, f_ftop, f_goff, f_foff;
!       tree ovfl, top, off, align;
!       HOST_WIDE_INT osize;
  
!       f_ovfl = TYPE_FIELDS (va_list_type_node);
!       f_gtop = TREE_CHAIN (f_ovfl);
!       f_ftop = TREE_CHAIN (f_gtop);
!       f_goff = TREE_CHAIN (f_ftop);
!       f_foff = TREE_CHAIN (f_goff);
  
!       /* We maintain separate pointers and offsets for floating-point
! 	 and integer arguments, but we need similar code in both cases.
! 	 Let:
  
! 	 TOP be the top of the register save area;
! 	 OFF be the offset from TOP of the next register;
! 	 ADDR_RTX be the address of the argument;
! 	 RSIZE be the number of bytes used to store the argument
! 	 when it's in the register save area;
! 	 OSIZE be the number of bytes used to store it when it's
! 	 in the stack overflow area; and
! 	 PADDING be (BYTES_BIG_ENDIAN ? OSIZE - RSIZE : 0)
  
! 	 The code we want is:
  
! 	 1: off &= -rsize;	  // round down
! 	 2: if (off != 0)
! 	 3:   {
! 	 4:	 addr_rtx = top - off;
! 	 5:	 off -= rsize;
! 	 6:   }
! 	 7: else
! 	 8:   {
! 	 9:	 ovfl += ((intptr_t) ovfl + osize - 1) & -osize;
! 	 10:	 addr_rtx = ovfl + PADDING;
! 	 11:	 ovfl += osize;
! 	 14:   }
  
! 	 [1] and [9] can sometimes be optimized away.  */
  
!       ovfl = build (COMPONENT_REF, TREE_TYPE (f_ovfl), valist, f_ovfl,
! 		    NULL_TREE);
  
!       if (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_FLOAT
! 	  && GET_MODE_SIZE (TYPE_MODE (type)) <= UNITS_PER_FPVALUE)
! 	{
! 	  top = build (COMPONENT_REF, TREE_TYPE (f_ftop), valist, f_ftop,
! 		       NULL_TREE);
! 	  off = build (COMPONENT_REF, TREE_TYPE (f_foff), valist, f_foff,
! 		       NULL_TREE);
  
! 	  /* When floating-point registers are saved to the stack,
! 	     each one will take up UNITS_PER_HWFPVALUE bytes, regardless
! 	     of the float's precision.  */
! 	  rsize = UNITS_PER_HWFPVALUE;
  
! 	  /* Overflow arguments are padded to UNITS_PER_WORD bytes
! 	     (= PARM_BOUNDARY bits).  This can be different from RSIZE
! 	     in two cases:
  
! 	     (1) On 32-bit targets when TYPE is a structure such as:
  
! 	     struct s { float f; };
  
! 	     Such structures are passed in paired FPRs, so RSIZE
! 	     will be 8 bytes.  However, the structure only takes
! 	     up 4 bytes of memory, so OSIZE will only be 4.
  
! 	     (2) In combinations such as -mgp64 -msingle-float
! 	     -fshort-double.  Doubles passed in registers
! 	     will then take up 4 (UNITS_PER_HWFPVALUE) bytes,
! 	     but those passed on the stack take up
! 	     UNITS_PER_WORD bytes.  */
! 	  osize = MAX (GET_MODE_SIZE (TYPE_MODE (type)), UNITS_PER_WORD);
! 	}
!       else
! 	{
! 	  top = build (COMPONENT_REF, TREE_TYPE (f_gtop), valist, f_gtop,
! 		       NULL_TREE);
! 	  off = build (COMPONENT_REF, TREE_TYPE (f_goff), valist, f_goff,
! 		       NULL_TREE);
! 	  if (rsize > UNITS_PER_WORD)
  	    {
! 	      /* [1] Emit code for: off &= -rsize.	*/
! 	      t = build (BIT_AND_EXPR, TREE_TYPE (off), off,
! 			 build_int_2 (-rsize, -1));
! 	      t = build (MODIFY_EXPR, TREE_TYPE (off), off, t);
! 	      gimplify_and_add (t, pre_p);
  	    }
+ 	  osize = rsize;
+ 	}
  
!       /* [2] Emit code to branch if off == 0.  */
!       t = lang_hooks.truthvalue_conversion (off);
!       addr = build (COND_EXPR, ptr_type_node, t, NULL, NULL);
  
!       /* [5] Emit code for: off -= rsize.  We do this as a form of
! 	 post-increment not available to C.  Also widen for the 
! 	 coming pointer arithmetic.  */
!       t = fold_convert (TREE_TYPE (off), build_int_2 (rsize, 0));
!       t = build (POSTDECREMENT_EXPR, TREE_TYPE (off), off, t);
!       t = fold_convert (sizetype, t);
!       t = fold_convert (TREE_TYPE (top), t);
  
!       /* [4] Emit code for: addr_rtx = top - off.  On big endian machines,
! 	 the argument has RSIZE - SIZE bytes of leading padding.  */
!       t = build (MINUS_EXPR, TREE_TYPE (top), top, t);
!       if (BYTES_BIG_ENDIAN && rsize > size)
  	{
! 	  u = fold_convert (TREE_TYPE (t), build_int_2 (rsize - size, 0));
! 	  t = build (PLUS_EXPR, TREE_TYPE (t), t, u);
  	}
!       COND_EXPR_THEN (addr) = t;
  
!       if (osize > UNITS_PER_WORD)
! 	{
! 	  /* [9] Emit: ovfl += ((intptr_t) ovfl + osize - 1) & -osize.  */
! 	  u = fold_convert (TREE_TYPE (ovfl), build_int_2 (osize - 1, 0));
! 	  t = build (PLUS_EXPR, TREE_TYPE (ovfl), ovfl, u);
! 	  u = fold_convert (TREE_TYPE (ovfl), build_int_2 (-osize, -1));
! 	  t = build (BIT_AND_EXPR, TREE_TYPE (ovfl), t, u);
! 	  align = build (MODIFY_EXPR, TREE_TYPE (ovfl), ovfl, t);
! 	}
        else
! 	align = NULL;
  
!       /* [10, 11].	Emit code to store ovfl in addr_rtx, then
! 	 post-increment ovfl by osize.  On big-endian machines,
! 	 the argument has OSIZE - SIZE bytes of leading padding.  */
!       u = fold_convert (TREE_TYPE (ovfl), build_int_2 (osize, 0));
!       t = build (POSTINCREMENT_EXPR, TREE_TYPE (ovfl), ovfl, u);
!       if (BYTES_BIG_ENDIAN && osize > size)
! 	{
! 	  u = fold_convert (TREE_TYPE (t), build_int_2 (osize - size, 0));
! 	  t = build (PLUS_EXPR, TREE_TYPE (t), t, u);
! 	}
  
!       /* String [9] and [10,11] together.  */
!       if (align)
! 	t = build (COMPOUND_EXPR, TREE_TYPE (t), align, t);
!       COND_EXPR_ELSE (addr) = t;
  
!       addr = fold_convert (build_pointer_type (type), addr);
!       addr = build_fold_indirect_ref (addr);
!     }
  
!   if (indirect)
!     addr = build_fold_indirect_ref (addr);
  
!   return addr;
  }
  \f
  /* Return true if it is possible to use left/right accesses for a
Index: mips.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.h,v
retrieving revision 1.347
diff -c -p -d -r1.347 mips.h
*** mips.h	7 Jul 2004 19:17:05 -0000	1.347
--- mips.h	9 Jul 2004 02:46:00 -0000
*************** typedef struct mips_args {
*** 2403,2412 ****
  /* Implement `va_start' for varargs and stdarg.  */
  #define EXPAND_BUILTIN_VA_START(valist, nextarg) \
    mips_va_start (valist, nextarg)
- 
- /* Implement `va_arg'.  */
- #define EXPAND_BUILTIN_VA_ARG(valist, type) \
-   mips_va_arg (valist, type)
  \f
  /* Output assembler code to FILE to increment profiler label # LABELNO
     for profiling a function entry.  */
--- 2403,2408 ----

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

* Re: gimple va_arg for mips
  2004-07-09  4:27 gimple va_arg for mips Richard Henderson
@ 2004-07-09  8:18 ` Richard Sandiford
  2004-07-09 10:05   ` Richard Henderson
  0 siblings, 1 reply; 12+ messages in thread
From: Richard Sandiford @ 2004-07-09  8:18 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, Eric Christopher

Richard Henderson <rth@redhat.com> writes:
> Ouch.  So, like, the mips maintainers have a choice to make.
>
> Patch 1 changes the ABI for !EABI such that variable sized types are
> passed by reference.  With this, we're able to pass them through varargs.
>
> The patch that was supposed to make that work,
>
> 2003-09-25  Richard Sandiford  <rsandifo@redhat.com>
>                                                                                 
>         PR target/6222
>         * config/mips/mips.c (mips_va_arg): Handle arguments that must be
>         passed on the stack.
>
> only works when va_arg is called from the same function that performed
> the va_start.  I'm not certain that I can replicate this hackery at the
> tree level, or if it's even desirable.

I guess I'm OK with changing the ABI.  We'll probably have to do
that anyway, what with the complex arg-passing problems. ;(

But does the above mean that MUST_PASS_IN_STACK now implies
"must be passed by reference", at least in some circumstances?
E.g., the following quote seems to suggest that pass-by-value
can still be used:

-------------------------------------------------------------------
... If @code{REG_PARM_STACK_SPACE}
is not defined and @code{FUNCTION_ARG} returns nonzero for such an
argument, the compiler will abort.  If @code{REG_PARM_STACK_SPACE} is
defined, the argument will be computed in the stack and then loaded into
a register.
-------------------------------------------------------------------

> In addition, there appears to have been an alignment and padding problem
> with the old code.  It didn't follow the same padding as the caller side.
> See PAD_VARARGS_DOWN.

Sorry to be clueless, but I don't see what you mean.  Is the mips
definition of PAD_VARARGS_DOWN wrong?  Or do you mean that the old
code wasn't honouring it?

The !EABI case used std_expand_builtin_va_arg while the EABI code
handles the padding itself.

FWIW, I've done a lot of testing on 3.4-era tools, all ABIs, both big
and little endian.  I haven't come across any varargs failures in the
testsuite.  Not that I'm saying that makes the code right.  Just a
datapoint...

I'll try to test patch 1 soon.  I suspect it'll need the following
as well.

Richard


Index: config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.426
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.426 mips.c
*** config/mips/mips.c	7 Jul 2004 19:24:28 -0000	1.426
--- config/mips/mips.c	9 Jul 2004 07:00:38 -0000
*************** mips_arg_info (const CUMULATIVE_ARGS *cu
*** 3611,3632 ****
  	even_reg_p = true;
      }
  
!   if (mips_abi != ABI_EABI && MUST_PASS_IN_STACK (mode, type))
!     /* This argument must be passed on the stack.  Eat up all the
!        remaining registers.  */
!     info->reg_offset = MAX_ARGS_IN_REGISTERS;
!   else
!     {
!       /* Set REG_OFFSET to the register count we're interested in.
! 	 The EABI allocates the floating-point registers separately,
! 	 but the other ABIs allocate them like integer registers.  */
!       info->reg_offset = (mips_abi == ABI_EABI && info->fpr_p
! 			  ? cum->num_fprs
! 			  : cum->num_gprs);
  
!       if (even_reg_p)
! 	info->reg_offset += info->reg_offset & 1;
!     }
  
    /* The alignment applied to registers is also applied to stack arguments.  */
    info->stack_offset = cum->stack_words;
--- 3619,3633 ----
  	even_reg_p = true;
      }
  
!   /* Set REG_OFFSET to the register count we're interested in.
!      The EABI allocates the floating-point registers separately,
!      but the other ABIs allocate them like integer registers.  */
!   info->reg_offset = (mips_abi == ABI_EABI && info->fpr_p
! 		      ? cum->num_fprs
! 		      : cum->num_gprs);
  
!   if (even_reg_p)
!     info->reg_offset += info->reg_offset & 1;
  
    /* The alignment applied to registers is also applied to stack arguments.  */
    info->stack_offset = cum->stack_words;

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

* Re: gimple va_arg for mips
  2004-07-09  8:18 ` Richard Sandiford
@ 2004-07-09 10:05   ` Richard Henderson
  2004-07-09 11:39     ` Richard Sandiford
  0 siblings, 1 reply; 12+ messages in thread
From: Richard Henderson @ 2004-07-09 10:05 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Eric Christopher

On Fri, Jul 09, 2004 at 08:03:46AM +0100, Richard Sandiford wrote:
> But does the above mean that MUST_PASS_IN_STACK now implies
> "must be passed by reference", at least in some circumstances?

In all circumstances, yes.

> E.g., the following quote seems to suggest that pass-by-value
> can still be used:

Possibly, yes.  I don't know that calls.c actually handles this
with variable sized arguments, but it might be possible.  Of
course, that doesn't apply to the newabi...

> > In addition, there appears to have been an alignment and padding problem
> > with the old code.  It didn't follow the same padding as the caller side.
> > See PAD_VARARGS_DOWN.
> 
> Sorry to be clueless, but I don't see what you mean.  Is the mips
> definition of PAD_VARARGS_DOWN wrong?  Or do you mean that the old
> code wasn't honouring it?

I mean that FUNCTION_ARG_PADDING computes some padding, up or down,
but the old code !EABI va_arg code always used pad up.  At least it
looked that way to me.

> I suspect it'll need the following as well.

Ah yes.


r~

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

* Re: gimple va_arg for mips
  2004-07-09 10:05   ` Richard Henderson
@ 2004-07-09 11:39     ` Richard Sandiford
  2004-07-09 12:34       ` Richard Henderson
  0 siblings, 1 reply; 12+ messages in thread
From: Richard Sandiford @ 2004-07-09 11:39 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, Eric Christopher

Richard Henderson <rth@redhat.com> writes:
>> E.g., the following quote seems to suggest that pass-by-value
>> can still be used:
>
> Possibly, yes.  I don't know that calls.c actually handles this
> with variable sized arguments, but it might be possible.  Of
> course, that doesn't apply to the newabi...

Right.  But the bit I quoted seemed to imply that (at least in the
old days) you could pass MUST_PASS_IN_STACK arguments by value as
long as you pass them on the stack.  The quote seemed to be saying
"oh, and if you define REG_PARM_STACK_SPACE, any part of the argument
in the reg parm rea will be loaded into the appropriate registers".

In the case of newabi, we were supposed to pass MUST_PASS_IN_STACK
arguments in the normal stack area, by value.  And it seemed to work.

So I'm still a little confused.  Are you saying that this was never
actually supported, but happened to work?  Or is it something that
used to be supported but isn't any more?

>> > In addition, there appears to have been an alignment and padding problem
>> > with the old code.  It didn't follow the same padding as the caller side.
>> > See PAD_VARARGS_DOWN.
>> 
>> Sorry to be clueless, but I don't see what you mean.  Is the mips
>> definition of PAD_VARARGS_DOWN wrong?  Or do you mean that the old
>> code wasn't honouring it?
>
> I mean that FUNCTION_ARG_PADDING computes some padding, up or down,
> but the old code !EABI va_arg code always used pad up.  At least it
> looked that way to me.

The down padding was supposed to be handled by:

          ...
	  if (BYTES_BIG_ENDIAN)
	    addr_rtx = plus_constant (addr_rtx, rsize - size);
          ...

for !EABI_FLOAT_VARARGS_P and:

          ...
	  if (BYTES_BIG_ENDIAN && osize > size)
	    t = build (PLUS_EXPR, TREE_TYPE (t), t,
		       build_int_2 (osize - size, 0));
          ...

for EABI_FLOAT_VARARGS_P.

Richard

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

* Re: gimple va_arg for mips
  2004-07-09 11:39     ` Richard Sandiford
@ 2004-07-09 12:34       ` Richard Henderson
  2004-07-09 19:31         ` Richard Sandiford
  0 siblings, 1 reply; 12+ messages in thread
From: Richard Henderson @ 2004-07-09 12:34 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Eric Christopher

On Fri, Jul 09, 2004 at 11:21:50AM +0100, Richard Sandiford wrote:
> In the case of newabi, we were supposed to pass MUST_PASS_IN_STACK
> arguments in the normal stack area, by value.  And it seemed to work.

It *will* work, for normal argument passing.  But you can't make
va_arg work with this scheme, with just "typedef void *va_list".

> The down padding was supposed to be handled by:
> 
>           ...
> 	  if (BYTES_BIG_ENDIAN)
> 	    addr_rtx = plus_constant (addr_rtx, rsize - size);
>           ...
> 
> for !EABI_FLOAT_VARARGS_P and:
> 
>           ...
> 	  if (BYTES_BIG_ENDIAN && osize > size)
> 	    t = build (PLUS_EXPR, TREE_TYPE (t), t,
> 		       build_int_2 (osize - size, 0));
>           ...

There are two components to padding.  That's one of them.  The other
is how you align the slot.  In particular, 

      if (!PAD_VARARGS_DOWN)
        {
          t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
                      build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp,
                              build_int_2 (boundary / BITS_PER_UNIT - 1, 0)));
          gimplify_and_add (t, pre_p);
        }
      t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
                  build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist_tmp,
                          build_int_2 (~(boundary / BITS_PER_UNIT - 1), -1)));

vs

      t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
                 build_int_2 (align - 1, 0));
      t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));

for !EABI.


r~

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

* Re: gimple va_arg for mips
  2004-07-09 12:34       ` Richard Henderson
@ 2004-07-09 19:31         ` Richard Sandiford
  2004-07-09 19:51           ` Richard Henderson
  0 siblings, 1 reply; 12+ messages in thread
From: Richard Sandiford @ 2004-07-09 19:31 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, Eric Christopher

Richard Henderson <rth@redhat.com> writes:
> On Fri, Jul 09, 2004 at 11:21:50AM +0100, Richard Sandiford wrote:
>> In the case of newabi, we were supposed to pass MUST_PASS_IN_STACK
>> arguments in the normal stack area, by value.  And it seemed to work.
>
> It *will* work, for normal argument passing.  But you can't make
> va_arg work with this scheme, with just "typedef void *va_list".

Ah, OK, I get it now, thanks.  I hadn't twigged that it was the
va_list that was problem.

> There are two components to padding.  That's one of them.  The other
> is how you align the slot.  In particular, 
>
>       if (!PAD_VARARGS_DOWN)
>         {
>           t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
>                       build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp,
>                               build_int_2 (boundary / BITS_PER_UNIT - 1, 0)));
>           gimplify_and_add (t, pre_p);
>         }
>       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
>                   build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist_tmp,
>                           build_int_2 (~(boundary / BITS_PER_UNIT - 1), -1)));
>
> vs
>
>       t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
>                  build_int_2 (align - 1, 0));
>       t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
>
> for !EABI.

Well, I feel I'm being stupid once again ;), but the mips.c version looks
more correct to me.  Why is the addition only applied if !PAD_VARARGS_DOWN?
What happens if:

  (a) PARM_BOUNDARY == 32
  (b) PAD_VARARGS_DOWN is true
  (c) the first vararg is a 32-bit value that happens to be passed
      at a 64-bit-aligned address
  (d) the second vararg is a 64-bit value with 64-bit alignment.

Won't conditionalising the addition on !PAD_VARARGS_DOWN mean
that we read the second argument from the same address as the first?

For example, I just tried the attached program on mips-elf.  It passes
before the patch but fails after it.  The code for foo() after the
patch looks like:

	addiu	$sp,$sp,-8
	lw	$4,24($sp)     # int arg
	lw	$3,28($sp)     # second word of long long arg
	lw	$2,24($sp)     # first word of long long arg
	addiu	$sp,$sp,8
	sw	$4,%gp_rel(gi)($28)
	sw	$3,%gp_rel(gll+4)($28)
	j	$31
	sw	$2,%gp_rel(gll)($28)

which is clearly wrong.  (Even so, it's much, much cleaner than the
code we used to get.  Very nice!)

Richard


#include <stdarg.h>

int gi;
long long gll;

void foo (long long l1, long long l2, ...)
{
  va_list ap;

  va_start (ap, l2);
  gi = va_arg (ap, int);
  gll = va_arg (ap, long long);
  va_end (ap);
}

int main ()
{
  foo (10LL, 11LL, 12, 13LL);
  if (gi != 12 || gll != 13LL)
    abort ();
  exit (0);
}

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

* Re: gimple va_arg for mips
  2004-07-09 19:31         ` Richard Sandiford
@ 2004-07-09 19:51           ` Richard Henderson
  2004-07-10  3:55             ` Richard Henderson
  0 siblings, 1 reply; 12+ messages in thread
From: Richard Henderson @ 2004-07-09 19:51 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Eric Christopher

On Fri, Jul 09, 2004 at 06:48:36PM +0100, Richard Sandiford wrote:
> Well, I feel I'm being stupid once again ;), but the mips.c version looks
> more correct to me.  Why is the addition only applied if !PAD_VARARGS_DOWN?

You're right.  I think this check was supposed to be for ARGS_GROW_DOWNWARD.
I wonder how this has gone unnoticed so long...  I'll fix it.


r~

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

* Re: gimple va_arg for mips
  2004-07-09 19:51           ` Richard Henderson
@ 2004-07-10  3:55             ` Richard Henderson
  2004-07-10 11:21               ` Richard Sandiford
  2004-07-10 12:47               ` Richard Henderson
  0 siblings, 2 replies; 12+ messages in thread
From: Richard Henderson @ 2004-07-10  3:55 UTC (permalink / raw)
  To: Richard Sandiford, gcc-patches, Eric Christopher

On Fri, Jul 09, 2004 at 12:12:17PM -0700, Richard Henderson wrote:
> You're right.  I think this check was supposed to be for ARGS_GROW_DOWNWARD.
> I wonder how this has gone unnoticed so long...  I'll fix it.

Like so.  Fully tested on i686; I'll build a mips-sim sometime
this weekend, but feel free to beat me to it.


r~


        * builtins.c (std_gimplify_va_arg_expr): Deny ARGS_GROW_DOWNWARD.
        Always align upward to arg boundary.  Use size_in_bytes/round_up.
        Maintain type-correctness of constants.
        * stor-layout.c (round_up, round_down): Special-case powers of 2.

Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.355
diff -c -p -d -r1.355 builtins.c
*** builtins.c	9 Jul 2004 23:04:32 -0000	1.355
--- builtins.c	10 Jul 2004 01:49:24 -0000
*************** expand_builtin_va_arg (tree valist, tree
*** 4473,4544 ****
  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, malign;
!   tree rounded_size;
!   tree valist_tmp;
!   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);
!   malign = size_int (-(PARM_BOUNDARY / BITS_PER_UNIT));
    boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type);
  
    valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
  
    /* 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_tmp,
! 		      build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp,
! 			      build_int_2 (boundary / BITS_PER_UNIT - 1, 0)));
! 	  gimplify_and_add (t, pre_p);
! 	}
        t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
! 		  build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist_tmp,
! 			  build_int_2 (~(boundary / BITS_PER_UNIT - 1), -1)));
        gimplify_and_add (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 (BIT_AND_EXPR, sizetype,
- 				   rounded_size, malign));
      }
  
    /* Reduce rounded_size so it's sharable with the postqueue.  */
    gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
  
    /* Get AP.  */
    addr = valist_tmp;
!   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))))));
      }
  
    /* Compute new value for AP.  */
!   t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
! 	      fold (build2 (PLUS_EXPR, TREE_TYPE (valist),
! 			    valist_tmp, rounded_size)));
    gimplify_and_add (t, pre_p);
  
    addr = fold_convert (build_pointer_type (type), addr);
--- 4473,4533 ----
  tree
  std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
  {
!   tree addr, t, type_size, rounded_size, valist_tmp;
!   unsigned int align, boundary;
! 
! #ifdef ARGS_GROW_DOWNWARD
!   /* All of the alignment and movement below is for args-grow-up machines.
!      As of 2004, there are only 3 ARGS_GROW_DOWNWARD targets, and they all
!      implement their own specialized gimplify_va_arg_expr routines.  */
!   abort ();
! #endif
  
    /* Compute the rounded size of the type.  */
!   align = PARM_BOUNDARY / BITS_PER_UNIT;
    boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type);
  
+   /* Hoist the valist value into a temporary for the moment.  */
    valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
  
    /* va_list pointer is aligned to PARM_BOUNDARY.  If argument actually
       requires greater alignment, we must perform dynamic alignment.  */
    if (boundary > PARM_BOUNDARY)
      {
!       unsigned byte_bound = boundary / BITS_PER_UNIT;
! 
!       t = fold_convert (TREE_TYPE (valist), size_int (byte_bound - 1));
        t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
! 		  build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t));
!       gimplify_and_add (t, pre_p);
! 
!       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
! 		  build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist_tmp, t));
        gimplify_and_add (t, pre_p);
      }
  
+   type_size = size_in_bytes (type);
+   rounded_size = round_up (type_size, align);
+ 
    /* Reduce rounded_size so it's sharable with the postqueue.  */
    gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
  
    /* Get AP.  */
    addr = valist_tmp;
!   if (PAD_VARARGS_DOWN && !integer_zerop (rounded_size))
      {
        /* Small args are padded downward.  */
!       t = fold (build2 (GT_EXPR, sizetype, rounded_size, size_int (align)));
!       t = fold (build3 (COND_EXPR, sizetype, t, size_zero_node,
! 			size_binop (MINUS_EXPR, rounded_size, type_size)));
!       t = fold_convert (TREE_TYPE (addr), t);
!       addr = build2 (PLUS_EXPR, TREE_TYPE (addr), addr, t);
      }
  
    /* Compute new value for AP.  */
!   t = fold_convert (TREE_TYPE (valist), rounded_size);
!   t = build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t);
!   t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
    gimplify_and_add (t, pre_p);
  
    addr = fold_convert (build_pointer_type (type), addr);
Index: stor-layout.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stor-layout.c,v
retrieving revision 1.194
diff -c -p -d -r1.194 stor-layout.c
*** stor-layout.c	3 Jul 2004 00:15:43 -0000	1.194
--- stor-layout.c	10 Jul 2004 01:49:24 -0000
*************** get_mode_alignment (enum machine_mode mo
*** 274,282 ****
  tree
  round_up (tree value, int divisor)
  {
!   tree arg = size_int_type (divisor, TREE_TYPE (value));
  
!   return size_binop (MULT_EXPR, size_binop (CEIL_DIV_EXPR, value, arg), arg);
  }
  
  /* Likewise, but round down.  */
--- 274,297 ----
  tree
  round_up (tree value, int divisor)
  {
!   tree t;
  
!   /* If divisor is a power of two, simplify this to bit manipulation.  */
!   if (divisor == (divisor & -divisor))
!     {
!       t = size_int_type (divisor - 1, TREE_TYPE (value));
!       value = size_binop (PLUS_EXPR, value, t);
!       t = size_int_type (-divisor, TREE_TYPE (value));
!       value = size_binop (BIT_AND_EXPR, value, t);
!     }
!   else
!     {
!       t = size_int_type (divisor, TREE_TYPE (value));
!       value = size_binop (CEIL_DIV_EXPR, value, t);
!       value = size_binop (MULT_EXPR, value, t);
!     }
! 
!   return value;
  }
  
  /* Likewise, but round down.  */
*************** round_up (tree value, int divisor)
*** 284,292 ****
  tree
  round_down (tree value, int divisor)
  {
!   tree arg = size_int_type (divisor, TREE_TYPE (value));
  
!   return size_binop (MULT_EXPR, size_binop (FLOOR_DIV_EXPR, value, arg), arg);
  }
  \f
  /* Subroutine of layout_decl: Force alignment required for the data type.
--- 299,320 ----
  tree
  round_down (tree value, int divisor)
  {
!   tree t;
  
!   /* If divisor is a power of two, simplify this to bit manipulation.  */
!   if (divisor == (divisor & -divisor))
!     {
!       t = size_int_type (-divisor, TREE_TYPE (value));
!       value = size_binop (BIT_AND_EXPR, value, t);
!     }
!   else
!     {
!       t = size_int_type (divisor, TREE_TYPE (value));
!       value = size_binop (FLOOR_DIV_EXPR, value, t);
!       value = size_binop (MULT_EXPR, value, t);
!     }
! 
!   return value;
  }
  \f
  /* Subroutine of layout_decl: Force alignment required for the data type.

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

* Re: gimple va_arg for mips
  2004-07-10  3:55             ` Richard Henderson
@ 2004-07-10 11:21               ` Richard Sandiford
  2004-07-11 10:58                 ` Richard Sandiford
  2004-07-10 12:47               ` Richard Henderson
  1 sibling, 1 reply; 12+ messages in thread
From: Richard Sandiford @ 2004-07-10 11:21 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, Eric Christopher

Richard Henderson <rth@redhat.com> writes:
> On Fri, Jul 09, 2004 at 12:12:17PM -0700, Richard Henderson wrote:
>> You're right.  I think this check was supposed to be for ARGS_GROW_DOWNWARD.
>> I wonder how this has gone unnoticed so long...  I'll fix it.
>
> Like so.  Fully tested on i686; I'll build a mips-sim sometime
> this weekend, but feel free to beat me to it.

Thanks, I'll give it a go on some mips targets and let you know.
Should have the results by about this time tomorrow.

Richard

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

* Re: gimple va_arg for mips
  2004-07-10  3:55             ` Richard Henderson
  2004-07-10 11:21               ` Richard Sandiford
@ 2004-07-10 12:47               ` Richard Henderson
  1 sibling, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2004-07-10 12:47 UTC (permalink / raw)
  To: Richard Sandiford, gcc-patches, Eric Christopher

Good heavens, today was not my day.


r~


        * builtins.c (std_gimplify_va_arg_expr): Fix borked BIT_AND_EXPR.

Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.357
diff -c -p -d -u -r1.357 builtins.c
--- builtins.c	10 Jul 2004 02:21:12 -0000	1.357
+++ builtins.c	10 Jul 2004 07:21:27 -0000
@@ -4483,29 +4483,28 @@ std_gimplify_va_arg_expr (tree valist, t
   abort ();
 #endif
 
-  /* Compute the rounded size of the type.  */
   align = PARM_BOUNDARY / BITS_PER_UNIT;
-  boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type);
+  boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type) / BITS_PER_UNIT;
 
   /* Hoist the valist value into a temporary for the moment.  */
   valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
 
   /* va_list pointer is aligned to PARM_BOUNDARY.  If argument actually
      requires greater alignment, we must perform dynamic alignment.  */
-  if (boundary > PARM_BOUNDARY)
+  if (boundary > align)
     {
-      unsigned byte_bound = boundary / BITS_PER_UNIT;
-
-      t = fold_convert (TREE_TYPE (valist), size_int (byte_bound - 1));
+      t = fold_convert (TREE_TYPE (valist), size_int (boundary - 1));
       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
 		  build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t));
       gimplify_and_add (t, pre_p);
 
+      t = fold_convert (TREE_TYPE (valist), size_int (-boundary));
       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
 		  build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist_tmp, t));
       gimplify_and_add (t, pre_p);
     }
 
+  /* Compute the rounded size of the type.  */
   type_size = size_in_bytes (type);
   rounded_size = round_up (type_size, align);
 

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

* Re: gimple va_arg for mips
  2004-07-10 11:21               ` Richard Sandiford
@ 2004-07-11 10:58                 ` Richard Sandiford
  2004-07-12 22:27                   ` Eric Christopher
  0 siblings, 1 reply; 12+ messages in thread
From: Richard Sandiford @ 2004-07-11 10:58 UTC (permalink / raw)
  To: Richard Henderson; +Cc: gcc-patches, Eric Christopher

Richard Sandiford <rsandifo@redhat.com> writes:
> Richard Henderson <rth@redhat.com> writes:
>> On Fri, Jul 09, 2004 at 12:12:17PM -0700, Richard Henderson wrote:
>>> You're right.  I think this check was supposed to be for ARGS_GROW_DOWNWARD.
>>> I wonder how this has gone unnoticed so long...  I'll fix it.
>>
>> Like so.  Fully tested on i686; I'll build a mips-sim sometime
>> this weekend, but feel free to beat me to it.
>
> Thanks, I'll give it a go on some mips targets and let you know.
> Should have the results by about this time tomorrow.

OK, bootstrapped & regression tested on mips64-linux-gnu and
mips64el-linux-gnu using the d-mips-1 patch, the patch to
mips_arg_info() (reproduced below with changelog) and the two
builtins patches.  The o32 and n32 multilibs were fine.
The n64 multilibs had many more failures, in execute/va-arg-*.c
and compat/*.c, but a quick check suggests that your patch
in the hppa thread fixes this.

Also tested on mipsisa64-elf ({-EB,-EL}{-mips64,-mips32}) to
get some EABI coverage.  No problems there.

So the mips stuff looks good to go.  Eric hasn't said whether
he's happy with the ABI change or not, but it's something we
can decide later anyway if necessary.

Richard


	* config/mips/mips.c (mips_arg_info): Remove special handling of
	MUST_PASS_IN_STACK arguments; assume they are passed by reference
	instead.

Index: config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.426
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.426 mips.c
*** config/mips/mips.c	7 Jul 2004 19:24:28 -0000	1.426
--- config/mips/mips.c	9 Jul 2004 07:00:38 -0000
*************** mips_arg_info (const CUMULATIVE_ARGS *cu
*** 3611,3632 ****
  	even_reg_p = true;
      }
  
!   if (mips_abi != ABI_EABI && MUST_PASS_IN_STACK (mode, type))
!     /* This argument must be passed on the stack.  Eat up all the
!        remaining registers.  */
!     info->reg_offset = MAX_ARGS_IN_REGISTERS;
!   else
!     {
!       /* Set REG_OFFSET to the register count we're interested in.
! 	 The EABI allocates the floating-point registers separately,
! 	 but the other ABIs allocate them like integer registers.  */
!       info->reg_offset = (mips_abi == ABI_EABI && info->fpr_p
! 			  ? cum->num_fprs
! 			  : cum->num_gprs);
  
!       if (even_reg_p)
! 	info->reg_offset += info->reg_offset & 1;
!     }
  
    /* The alignment applied to registers is also applied to stack arguments.  */
    info->stack_offset = cum->stack_words;
--- 3619,3633 ----
  	even_reg_p = true;
      }
  
!   /* Set REG_OFFSET to the register count we're interested in.
!      The EABI allocates the floating-point registers separately,
!      but the other ABIs allocate them like integer registers.  */
!   info->reg_offset = (mips_abi == ABI_EABI && info->fpr_p
! 		      ? cum->num_fprs
! 		      : cum->num_gprs);
  
!   if (even_reg_p)
!     info->reg_offset += info->reg_offset & 1;
  
    /* The alignment applied to registers is also applied to stack arguments.  */
    info->stack_offset = cum->stack_words;

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

* Re: gimple va_arg for mips
  2004-07-11 10:58                 ` Richard Sandiford
@ 2004-07-12 22:27                   ` Eric Christopher
  0 siblings, 0 replies; 12+ messages in thread
From: Eric Christopher @ 2004-07-12 22:27 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: Richard Henderson, gcc-patches

On Sat, 2004-07-10 at 23:35, Richard Sandiford wrote:
> Richard Sandiford <rsandifo@redhat.com> writes:

> So the mips stuff looks good to go.  Eric hasn't said whether
> he's happy with the ABI change or not, but it's something we
> can decide later anyway if necessary.

Sorry. thought I had. I'm good.

-eric

-- 
Eric Christopher <echristo@redhat.com>

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

end of thread, other threads:[~2004-07-12 17:55 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-07-09  4:27 gimple va_arg for mips Richard Henderson
2004-07-09  8:18 ` Richard Sandiford
2004-07-09 10:05   ` Richard Henderson
2004-07-09 11:39     ` Richard Sandiford
2004-07-09 12:34       ` Richard Henderson
2004-07-09 19:31         ` Richard Sandiford
2004-07-09 19:51           ` Richard Henderson
2004-07-10  3:55             ` Richard Henderson
2004-07-10 11:21               ` Richard Sandiford
2004-07-11 10:58                 ` Richard Sandiford
2004-07-12 22:27                   ` Eric Christopher
2004-07-10 12:47               ` Richard Henderson

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).