[patches] Re: x86_64 merger part 39 - vardic functions..

Jan Hubicka jh@suse.cz
Thu Sep 20 05:58:00 GMT 2001


> On Thu, 20 Sep 2001, Jan Hubicka wrote:
> > Thu Sep 20 14:44:50 CEST 2001  Jan Hubicka  <jh@suse.cz>
> >
> > 	* i386-protos.h (ix86_setup_incoming_varargs, ix86_va_arg,
> > 	ix86_va_start, ix86_build_va_list): Declare.
> > 	* i386.c (ix86_setup_incoming_varargs, ix86_va_arg,
> > 	ix86_va_start, ix86_build_va_list): New global functions.
> > 	* i386.md (sse_prologue_save_insn): New insn.
> > 	(sse_prologue_save): New expander.
> > 	* i386.h (EXPAND_BUILTIN_VA_ARG, EXPAND_BUILTIN_VA_START,
> > 	BUILD_VA_LIST_TYPE, SETUP_INCOMING_VARARGS): New macros.
> 
> There are a couple of overly long lines in this patch.
oops, forgot to check.

Here is updated patch, hopefully now in the needed limits.

diff -Nrc3p i386.nova/i386-protos.h i386/i386-protos.h
*** i386.nova/i386-protos.h	Thu Sep 20 14:19:39 2001
--- i386/i386-protos.h	Thu Sep 20 14:25:57 2001
*************** extern bool ix86_function_value_regno_p 
*** 140,145 ****
--- 140,150 ----
  extern bool ix86_function_arg_regno_p PARAMS ((int));
  extern int ix86_function_arg_boundary PARAMS ((enum machine_mode, tree));
  extern int ix86_return_in_memory PARAMS ((tree));
+ extern void ix86_va_start PARAMS ((int, tree, rtx));
+ extern rtx ix86_va_arg PARAMS ((tree, tree));
+ extern void ix86_setup_incoming_varargs PARAMS ((CUMULATIVE_ARGS *,
+ 						 enum machine_mode,
+ 						 tree, int *, int));
  
  extern rtx ix86_force_to_memory PARAMS ((enum machine_mode, rtx));
  extern void ix86_free_from_memory PARAMS ((enum machine_mode));
*************** extern rtx ix86_expand_builtin PARAMS ((
*** 175,180 ****
--- 180,186 ----
  
  #ifdef TREE_CODE
  extern int ix86_return_pops_args PARAMS ((tree, tree, int));
+ extern tree ix86_build_va_list PARAMS ((void));
  
  extern int ix86_data_alignment PARAMS ((tree, int));
  extern int ix86_local_alignment PARAMS ((tree, int));
diff -Nrc3p i386.nova/i386.c i386/i386.c
*** i386.nova/i386.c	Thu Sep 20 14:19:39 2001
--- i386/i386.c	Thu Sep 20 14:56:33 2001
*************** ix86_libcall_value (mode)
*** 2024,2033 ****
    else
     return gen_rtx_REG (mode, VALUE_REGNO (mode));
  }
  
  
! 
  
  /* Return nonzero if OP is general operand representable on x86_64.  */
  
  int
--- 2024,2478 ----
    else
     return gen_rtx_REG (mode, VALUE_REGNO (mode));
  }
+ 
+ /* Create the va_list data type.  */
  
+ tree
+ ix86_build_va_list ()
+ {
+   tree f_gpr, f_fpr, f_ovf, f_sav, record, type_decl;
  
!   /* For i386 we use plain pointer to argument area.  */
!   if (!TARGET_64BIT)
!     return build_pointer_type (char_type_node);
! 
!   record = make_lang_type (RECORD_TYPE);
!   type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
! 
!   f_gpr = build_decl (FIELD_DECL, get_identifier ("gp_offset"), 
! 		      unsigned_type_node);
!   f_fpr = build_decl (FIELD_DECL, get_identifier ("fp_offset"), 
! 		      unsigned_type_node);
!   f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"),
! 		      ptr_type_node);
!   f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
! 		      ptr_type_node);
! 
!   DECL_FIELD_CONTEXT (f_gpr) = record;
!   DECL_FIELD_CONTEXT (f_fpr) = record;
!   DECL_FIELD_CONTEXT (f_ovf) = record;
!   DECL_FIELD_CONTEXT (f_sav) = record;
! 
!   TREE_CHAIN (record) = type_decl;
!   TYPE_NAME (record) = type_decl;
!   TYPE_FIELDS (record) = f_gpr;
!   TREE_CHAIN (f_gpr) = f_fpr;
!   TREE_CHAIN (f_fpr) = f_ovf;
!   TREE_CHAIN (f_ovf) = f_sav;
! 
!   layout_type (record);
! 
!   /* The correct type is an array type of one element.  */
!   return build_array_type (record, build_index_type (size_zero_node));
! }
! 
! /* Perform any needed actions needed for a function that is receiving a
!    variable number of arguments. 
! 
!    CUM is as above.
! 
!    MODE and TYPE are the mode and type of the current parameter.
! 
!    PRETEND_SIZE is a variable that should be set to the amount of stack
!    that must be pushed by the prolog to pretend that our caller pushed
!    it.
! 
!    Normally, this macro will push all remaining incoming registers on the
!    stack and set PRETEND_SIZE to the length of the registers pushed.  */
! 
! void
! ix86_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
!      CUMULATIVE_ARGS *cum;
!      enum machine_mode mode;
!      tree type;
!      int *pretend_size ATTRIBUTE_UNUSED;
!      int no_rtl;
! 
! {
!   CUMULATIVE_ARGS next_cum;
!   rtx save_area = NULL_RTX, mem;
!   rtx label;
!   rtx label_ref;
!   rtx tmp_reg;
!   rtx nsse_reg;
!   int set;
!   tree fntype;
!   int stdarg_p;
!   int i;
! 
!   if (!TARGET_64BIT)
!     return;
! 
!   /* Indicate to allocate space on the stack for varargs save area.  */
!   ix86_save_varrargs_registers = 1;
! 
!   fntype = TREE_TYPE (current_function_decl);
!   stdarg_p = (TYPE_ARG_TYPES (fntype) != 0
! 	      && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
! 		  != void_type_node));
! 
!   /* For varargs, we do not want to skip the dummy va_dcl argument.
!      For stdargs, we do want to skip the last named argument.  */
!   next_cum = *cum;
!   if (stdarg_p)
!     function_arg_advance (&next_cum, mode, type, 1);
! 
!   if (!no_rtl)
!     save_area = frame_pointer_rtx;
! 
!   set = get_varargs_alias_set ();
! 
!   for (i = next_cum.regno; i < ix86_regparm; i++)
!     {
!       mem = gen_rtx_MEM (Pmode,
! 			 plus_constant (save_area, i * UNITS_PER_WORD));
!       MEM_ALIAS_SET (mem) = set;
!       emit_move_insn (mem, gen_rtx_REG (Pmode,
! 					x86_64_int_parameter_registers[i]));
!     }
! 
!   if (next_cum.sse_nregs)
!     {
!       /* Now emit code to save SSE registers.  The AX parameter contains number
! 	 of SSE parameter regsiters used to call this function.  We use
! 	 sse_prologue_save insn template that produces computed jump across
! 	 SSE saves.  We need some preparation work to get this working.  */
! 
!       label = gen_label_rtx ();
!       label_ref = gen_rtx_LABEL_REF (Pmode, label);
! 
!       /* Compute address to jump to :
!          label - 5*eax + nnamed_sse_arguments*5  */
!       tmp_reg = gen_reg_rtx (Pmode);
!       nsse_reg = gen_reg_rtx (Pmode);
!       emit_insn (gen_zero_extendqidi2 (nsse_reg, gen_rtx_REG (QImode, 0)));
!       emit_insn (gen_rtx_SET (VOIDmode, tmp_reg,
! 			      gen_rtx_MULT (VOIDmode, nsse_reg,
! 					    GEN_INT (4))));
!       if (next_cum.sse_regno)
! 	emit_move_insn
! 	  (nsse_reg,
! 	   gen_rtx_CONST (DImode,
! 			  gen_rtx_PLUS (DImode,
! 					label_ref,
! 					GEN_INT (next_cum.sse_regno * 4))));
!       else
! 	emit_move_insn (nsse_reg, label_ref);
!       emit_insn (gen_subdi3 (nsse_reg, nsse_reg, tmp_reg));
! 
!       /* Compute address of memory block we save into.  We always use pointer
! 	 pointing 127 bytes after first byte to store - this is needed to keep
! 	 instruction size limited by 4 bytes.  */
!       tmp_reg = gen_reg_rtx (Pmode);
!       emit_insn (gen_rtx_SET(VOIDmode, tmp_reg,
! 			     plus_constant (save_area, 8 * REGPARM_MAX + 127)));
!       mem = gen_rtx_MEM (BLKmode, plus_constant (tmp_reg, -127));
!       MEM_ALIAS_SET (mem) = set;
! 
!       /* And finally do the dirty job!  */
!       emit_insn (gen_sse_prologue_save (mem, nsse_reg, GEN_INT (next_cum.sse_regno),
! 		 label));
!     }
! 
! }
! 
! /* Implement va_start.  */
! 
! void
! ix86_va_start (stdarg_p, valist, nextarg)
!      int stdarg_p;
!      tree valist;
!      rtx nextarg;
! {
!   HOST_WIDE_INT words, n_gpr, n_fpr;
!   tree f_gpr, f_fpr, f_ovf, f_sav;
!   tree gpr, fpr, ovf, sav, t;
! 
!   /* Only 64bit target needs something special.  */
!   if (!TARGET_64BIT)
!     {
!       std_expand_builtin_va_start (stdarg_p, valist, nextarg);
!       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 = 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);
  
+   /* Count number of gp and fp argument registers used.  */
+   words = current_function_args_info.words;
+   n_gpr = current_function_args_info.regno;
+   n_fpr = current_function_args_info.sse_regno;
+ 
+   if (TARGET_DEBUG_ARG)
+     fprintf (stderr, "va_start: words = %d, n_gpr = %d, n_fpr = %d\n",
+ 	     words, n_gpr, n_fpr);
+ 
+   t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr,
+ 	     build_int_2 (n_gpr * 8, 0));
+   TREE_SIDE_EFFECTS (t) = 1;
+   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ 
+   t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr,
+ 	     build_int_2 (n_fpr * 16 + 8*REGPARM_MAX, 0));
+   TREE_SIDE_EFFECTS (t) = 1;
+   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ 
+   /* Find the overflow area.  */
+   t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
+   if (words != 0)
+     t = build (PLUS_EXPR, TREE_TYPE (ovf), t,
+ 	       build_int_2 (words * UNITS_PER_WORD, 0));
+   t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
+   TREE_SIDE_EFFECTS (t) = 1;
+   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ 
+   /* Find the register save area.
+      Prologue of the function save it right above stack frame.  */
+   t = make_tree (TREE_TYPE (sav), frame_pointer_rtx);
+   t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
+   TREE_SIDE_EFFECTS (t) = 1;
+   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
+ 
+ /* Implement va_arg.  */
+ rtx
+ ix86_va_arg (valist, type)
+      tree valist, type;
+ {
+   static 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 indirect_p = 0, size, rsize;
+   rtx lab_false, lab_over = NULL_RTX;
+   rtx addr_rtx, r;
+   rtx container;
+ 
+   /* Only 64bit target needs something special.  */
+   if (!TARGET_64BIT)
+     {
+       return std_expand_builtin_va_arg (valist, type);
+     }
+ 
+   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 = 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 + 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_rtx = gen_reg_rtx (Pmode);
+ 
+   if (container)
+     {
+       rtx int_addr_rtx, sse_addr_rtx;
+       int needed_intregs, needed_sseregs;
+       int need_temp;
+ 
+       lab_over = gen_label_rtx ();
+       lab_false = gen_label_rtx ();
+ 
+       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 consetuctive 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 consetuctive  */
+ 	  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_rtx = addr_rtx;
+ 	  sse_addr_rtx = addr_rtx;
+ 	}
+       else
+ 	{
+ 	  int_addr_rtx = gen_reg_rtx (Pmode);
+ 	  sse_addr_rtx = gen_reg_rtx (Pmode);
+ 	}
+       /* First ensure that we fit completely in registers.  */
+       if (needed_intregs)
+ 	{
+ 	  emit_cmp_and_jump_insns (expand_expr
+ 				   (gpr, NULL_RTX, SImode, EXPAND_NORMAL),
+ 				   GEN_INT ((REGPARM_MAX - needed_intregs +
+ 					     1) * 8), GE, const1_rtx, SImode,
+ 				   1, 1, lab_false);
+ 	}
+       if (needed_sseregs)
+ 	{
+ 	  emit_cmp_and_jump_insns (expand_expr
+ 				   (fpr, NULL_RTX, SImode, EXPAND_NORMAL),
+ 				   GEN_INT ((SSE_REGPARM_MAX -
+ 					     needed_sseregs + 1) * 16 +
+ 					    REGPARM_MAX * 8), GE, const1_rtx,
+ 				   SImode, 1, 1, lab_false);
+ 	}
+ 
+       /* Compute index to start of area used for integer regs.  */
+       if (needed_intregs)
+ 	{
+ 	  t = build (PLUS_EXPR, ptr_type_node, sav, gpr);
+ 	  r = expand_expr (t, int_addr_rtx, Pmode, EXPAND_NORMAL);
+ 	  if (r != int_addr_rtx)
+ 	    emit_move_insn (int_addr_rtx, r);
+ 	}
+       if (needed_sseregs)
+ 	{
+ 	  t = build (PLUS_EXPR, ptr_type_node, sav, fpr);
+ 	  r = expand_expr (t, sse_addr_rtx, Pmode, EXPAND_NORMAL);
+ 	  if (r != sse_addr_rtx)
+ 	    emit_move_insn (sse_addr_rtx, r);
+ 	}
+       if (need_temp)
+ 	{
+ 	  int i;
+ 	  rtx mem;
+ 
+ 	  mem = assign_temp (type, 0, 1, 0);
+ 	  MEM_ALIAS_SET (mem) = get_varargs_alias_set ();
+ 	  addr_rtx = XEXP (mem, 0);
+ 	  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);
+ 	      rtx src_addr;
+ 	      rtx src_mem;
+ 	      int src_offset;
+ 	      rtx dest_mem;
+ 
+ 	      if (SSE_REGNO_P (REGNO (reg)))
+ 		{
+ 		  src_addr = sse_addr_rtx;
+ 		  src_offset = (REGNO (reg) - FIRST_SSE_REG) * 16;
+ 		}
+ 	      else
+ 		{
+ 		  src_addr = int_addr_rtx;
+ 		  src_offset = REGNO (reg) * 8;
+ 		}
+ 	      src_mem = gen_rtx_MEM (mode, src_addr);
+ 	      MEM_ALIAS_SET (src_mem) = get_varargs_alias_set ();
+ 	      src_mem = adjust_address (src_mem, mode, src_offset);
+ 	      dest_mem = adjust_address (mem, mode, INTVAL (XEXP (slot, 1)));
+ 	      PUT_MODE (dest_mem, mode);
+ 	      /* ??? Break out TImode moves from integer registers?  */
+ 	      emit_move_insn (dest_mem, src_mem);
+ 	    }
+ 	}
+ 
+       if (needed_intregs)
+ 	{
+ 	  t =
+ 	    build (PLUS_EXPR, TREE_TYPE (gpr), gpr,
+ 		   build_int_2 (needed_intregs * 8, 0));
+ 	  t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t);
+ 	  TREE_SIDE_EFFECTS (t) = 1;
+ 	  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ 	}
+       if (needed_sseregs)
+ 	{
+ 	  t =
+ 	    build (PLUS_EXPR, TREE_TYPE (fpr), fpr,
+ 		   build_int_2 (needed_sseregs * 16, 0));
+ 	  t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, t);
+ 	  TREE_SIDE_EFFECTS (t) = 1;
+ 	  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ 	}
+ 
+       emit_jump_insn (gen_jump (lab_over));
+       emit_barrier ();
+       emit_label (lab_false);
+     }
+ 
+   /* ... 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));
+     }
+   t = save_expr (t);
+ 
+   r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
+   if (r != addr_rtx)
+     emit_move_insn (addr_rtx, r);
+ 
+   t =
+     build (PLUS_EXPR, TREE_TYPE (t), t,
+ 	   build_int_2 (rsize * UNITS_PER_WORD, 0));
+   t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
+   TREE_SIDE_EFFECTS (t) = 1;
+   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ 
+   if (container)
+     emit_label (lab_over);
+ 
+   if (indirect_p)
+     {
+       abort ();
+       r = gen_rtx_MEM (Pmode, addr_rtx);
+       MEM_ALIAS_SET (r) = get_varargs_alias_set ();
+       emit_move_insn (addr_rtx, r);
+     }
+ 
+   return addr_rtx;
+ }
+ 
  /* Return nonzero if OP is general operand representable on x86_64.  */
  
  int
diff -Nrc3p i386.nova/i386.h i386/i386.h
*** i386.nova/i386.h	Thu Sep 20 14:19:40 2001
--- i386/i386.h	Thu Sep 20 14:25:11 2001
*************** typedef struct ix86_args {
*** 1604,1609 ****
--- 1604,1638 ----
         || ! FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (TREE_TYPE (DECL)))) \
         || FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (TREE_TYPE (cfun->decl))))))
  
+ /* Perform any needed actions needed for a function that is receiving a
+    variable number of arguments.
+ 
+    CUM is as above.
+ 
+    MODE and TYPE are the mode and type of the current parameter.
+ 
+    PRETEND_SIZE is a variable that should be set to the amount of stack
+    that must be pushed by the prolog to pretend that our caller pushed
+    it.
+ 
+    Normally, this macro will push all remaining incoming registers on the
+    stack and set PRETEND_SIZE to the length of the registers pushed.  */
+ 
+ #define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
+   ix86_setup_incoming_varargs (&CUM, MODE, TYPE, &PRETEND_SIZE, NO_RTL)
+ 
+ /* Define the `__builtin_va_list' type for the ABI.  */
+ #define BUILD_VA_LIST_TYPE(VALIST) \
+   (VALIST) = ix86_build_va_list ()
+ 
+ /* Implement `va_start' for varargs and stdarg.  */
+ #define EXPAND_BUILTIN_VA_START(stdarg, valist, nextarg) \
+   ix86_va_start (stdarg, valist, nextarg)
+ 
+ /* Implement `va_arg'.  */
+ #define EXPAND_BUILTIN_VA_ARG(valist, type) \
+   ix86_va_arg (valist, type)
+ 
  /* This macro is invoked at the end of compilation.  It is used here to
     output code for -fpic that will load the return address into %ebx.  */
  
*************** extern int const svr4_dbx_register_map[F
*** 2774,2779 ****
--- 2803,2809 ----
  /* Describe how we implement __builtin_eh_return.  */
  #define EH_RETURN_DATA_REGNO(N)	((N) < 2 ? (N) : INVALID_REGNUM)
  #define EH_RETURN_STACKADJ_RTX	gen_rtx_REG (Pmode, 2)
+ 
  
  /* Select a format to encode pointers in exception handling data.  CODE
     is 0 for data, 1 for code labels, 2 for function pointers.  GLOBAL is
diff -Nrc3p i386.nova/i386.md i386/i386.md
*** i386.nova/i386.md	Thu Sep 20 14:19:40 2001
--- i386/i386.md	Thu Sep 20 14:39:37 2001
***************
*** 19066,19068 ****
--- 19066,19128 ----
  }
    [(set_attr "type" "sse")])
  
+ (define_expand "sse_prologue_save"
+   [(parallel [(set (match_operand:BLK 0 "" "")
+ 		   (unspec:BLK [(clobber (reg:DI 21))
+ 				(clobber (reg:DI 22))
+ 				(clobber (reg:DI 23))
+ 				(clobber (reg:DI 24))
+ 				(clobber (reg:DI 25))
+ 				(clobber (reg:DI 26))
+ 				(clobber (reg:DI 27))
+ 				(clobber (reg:DI 28))] 13))
+ 	      (use (match_operand:DI 1 "register_operand" ""))
+ 	      (use (match_operand:DI 2 "immediate_operand" ""))
+ 	      (use (label_ref:DI (match_operand 3 "" "")))])]
+   "TARGET_64BIT"
+   "")
+ 
+ (define_insn "*sse_prologue_save_insn"
+   [(set (mem:BLK (plus:DI (match_operand:DI 0 "register_operand" "R")
+ 			  (match_operand:DI 4 "const_int_operand" "n")))
+ 	(unspec:BLK [(clobber (reg:DI 21))
+ 		     (clobber (reg:DI 22))
+ 		     (clobber (reg:DI 23))
+ 		     (clobber (reg:DI 24))
+ 		     (clobber (reg:DI 25))
+ 		     (clobber (reg:DI 26))
+ 		     (clobber (reg:DI 27))
+ 		     (clobber (reg:DI 28))] 13))
+    (use (match_operand:DI 1 "register_operand" "r"))
+    (use (match_operand:DI 2 "const_int_operand" "i"))
+    (use (label_ref:DI (match_operand 3 "" "X")))]
+   "TARGET_64BIT
+    && INTVAL (operands[4]) + SSE_REGPARM_MAX * 16 - 16 < 128
+    && INTVAL (operands[4]) + INTVAL (operands[2]) * 16 >= -128"
+   "*
+ {
+   int i;
+   operands[0] = gen_rtx_MEM (Pmode,
+ 			     gen_rtx_PLUS (Pmode, operands[0], operands[4]));
+   output_asm_insn (\"jmp\\t%A1\", operands);
+   for (i = SSE_REGPARM_MAX - 1; i >= INTVAL (operands[2]); i--)
+     {
+       operands[4] = adjust_address (operands[0], DImode, i*16);
+       operands[5] = gen_rtx_REG (TImode, SSE_REGNO (i));
+       PUT_MODE (operands[4], TImode);
+       if (GET_CODE (XEXP (operands[0], 0)) != PLUS)
+         output_asm_insn (\"rex\", operands);
+       output_asm_insn (\"movaps\\t{%5, %4|%4, %5}\", operands);
+     }
+   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
+ 			     CODE_LABEL_NUMBER (operands[3]));
+   RET;
+ }
+   "
+   [(set_attr "type" "other")
+    (set_attr "length_immediate" "0")
+    (set_attr "length_address" "0")
+    (set_attr "length" "135")
+    (set_attr "memory" "store")
+    (set_attr "modrm" "0")
+    (set_attr "mode" "DI")])



More information about the Gcc-patches mailing list