Regparm extension...

Jan Hubicka jh@suse.cz
Thu Jul 6 02:25:00 GMT 2000


Hi
This patch adds support for passing fp parameters on i387 stack.
This is controlled by optional second argument of regparm attribute
or via -mi387-regparm option.  While the benefits are quite marginal
for floats/doubles on currect x86 CPUs, but I have some other plans
for this code...

Honza

Wed Jul  5 23:39:43 CEST 2000  Jan Hubicka  <jh@suse.cz>

	* i386.c (ix86_i387_regparm_string, ix86_i387_regparm):
	New global variables.
	(override_options): Handle -mi387-regparm
	(ix86_valid_type_attribute_p): Allow optional second
	argument of regparm.
	(init_cumulucative_args): Init nfpregs and fpregno.
	(function_arg_advance): Advance fpregno when needed.
	(function_arg): Pass fp parameters in fp registers
	when available.
	* i386.h (TARGET_OPTIONS): Add "i387-regparm".
	(ix86_i387_regparm_string, ix86_i387_regparm): Declare.
	* reg-stack.c (convert_regs_entry): Put incomming
	args to stack correctly, pop unuset arguments off the
	stack.
	* invoke.texi (mi386-regparm): Document.
	* extend.texi (regparm): Update documentation.

*** i386.c.old	Wed Jul  5 16:48:36 2000
--- i386.c	Wed Jul  5 23:22:38 2000
*************** static char regs_allocated[FIRST_PSEUDO_
*** 363,371 ****
--- 363,377 ----
  /* # of registers to use to pass arguments. */
  const char *ix86_regparm_string;
  
+ /* # of i387 registers to use to pass arguments. */
+ const char *ix86_i387_regparm_string;
+ 
  /* ix86_regparm_string as a number */
  int ix86_regparm;
  
+ /* ix86_i387_regparm_string as a number */
+ int ix86_i387_regparm;
+ 
  /* Alignment to use for loops and jumps:  */
  
  /* Power of two alignment for loops. */
*************** override_options ()
*** 570,575 ****
--- 576,591 ----
  	       ix86_regparm, REGPARM_MAX);
      }
  
+   /* Validate -mi387-regparm= value. */
+   if (ix86_i387_regparm_string)
+     {
+       ix86_i387_regparm = atoi (ix86_i387_regparm_string);
+       if (ix86_i387_regparm < 0
+ 	  || ix86_i387_regparm > LAST_STACK_REG - FIRST_STACK_REG + 1)
+ 	fatal ("-mi387-regparm=%d is not between 0 and %d",
+ 	       ix86_i387_regparm, LAST_STACK_REG - FIRST_STACK_REG + 1);
+     }
+ 
    /* Validate -malign-loops= value, or provide default.  */
    ix86_align_loops = processor_target_table[ix86_cpu].align_loop;
    if (ix86_align_loops_string)
*************** ix86_valid_type_attribute_p (type, attri
*** 755,761 ****
        tree cst;
  
        if (! args || TREE_CODE (args) != TREE_LIST
! 	  || TREE_CHAIN (args) != NULL_TREE
  	  || TREE_VALUE (args) == NULL_TREE)
  	return 0;
  
--- 771,778 ----
        tree cst;
  
        if (! args || TREE_CODE (args) != TREE_LIST
! 	  || (TREE_CHAIN (args)
! 	      && TREE_CHAIN (TREE_CHAIN (args)) != NULL_TREE)
  	  || TREE_VALUE (args) == NULL_TREE)
  	return 0;
  
*************** ix86_valid_type_attribute_p (type, attri
*** 766,771 ****
--- 783,797 ----
        if (compare_tree_int (cst, REGPARM_MAX) > 0)
  	return 0;
  
+       if (TREE_CHAIN (args))
+ 	{
+ 	  cst = TREE_VALUE (TREE_CHAIN (args));
+ 	  if (TREE_CODE (cst) != INTEGER_CST)
+ 	    return 0;
+ 	  if (compare_tree_int (cst, LAST_STACK_REG - FIRST_STACK_REG + 1) > 0)
+ 	    return 0;
+ 	}
+ 
        return 1;
      }
  
*************** init_cumulative_args (cum, fntype, libna
*** 873,884 ****
  
    /* Set up the number of registers to use for passing arguments.  */
    cum->nregs = ix86_regparm;
    if (fntype)
      {
        tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype));
  
        if (attr)
! 	cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
      }
  
    /* Determine if this function has variable arguments.  This is
--- 899,917 ----
  
    /* Set up the number of registers to use for passing arguments.  */
    cum->nregs = ix86_regparm;
+   cum->nfpregs = ix86_i387_regparm;
+   cum->fpregno = FIRST_STACK_REG;
    if (fntype)
      {
        tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype));
  
        if (attr)
! 	{
! 	  cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
! 	  if (TREE_CHAIN (TREE_VALUE (attr)))
! 	    cum->nfpregs
! 	      = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (TREE_VALUE (attr))));
! 	}
      }
  
    /* Determine if this function has variable arguments.  This is
*************** init_cumulative_args (cum, fntype, libna
*** 886,904 ****
       are no variable arguments.  If there are variable arguments, then
       we won't pass anything in registers */
  
!   if (cum->nregs)
      {
        for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
  	   param != 0; param = next_param)
  	{
  	  next_param = TREE_CHAIN (param);
  	  if (next_param == 0 && TREE_VALUE (param) != void_type_node)
! 	    cum->nregs = 0;
  	}
      }
  
    if (TARGET_DEBUG_ARG)
!     fprintf (stderr, ", nregs=%d )\n", cum->nregs);
  
    return;
  }
--- 919,937 ----
       are no variable arguments.  If there are variable arguments, then
       we won't pass anything in registers */
  
!   if (cum->nregs || cum->nfpregs)
      {
        for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
  	   param != 0; param = next_param)
  	{
  	  next_param = TREE_CHAIN (param);
  	  if (next_param == 0 && TREE_VALUE (param) != void_type_node)
! 	    cum->nregs = 0, cum->nfpregs = 0;
  	}
      }
  
    if (TARGET_DEBUG_ARG)
!     fprintf (stderr, ", nregs=%d fpregs=%d)\n", cum->nregs, cum->nfpregs);
  
    return;
  }
*************** function_arg_advance (cum, mode, type, n
*** 920,937 ****
  
    if (TARGET_DEBUG_ARG)
      fprintf (stderr,
! 	     "function_adv (sz=%d, wds=%2d, nregs=%d, mode=%s, named=%d)\n\n",
! 	     words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
  
    cum->words += words;
    cum->nregs -= words;
    cum->regno += words;
  
    if (cum->nregs <= 0)
      {
        cum->nregs = 0;
        cum->regno = 0;
      }
  
    return;
  }
--- 953,977 ----
  
    if (TARGET_DEBUG_ARG)
      fprintf (stderr,
! 	     "function_adv (sz=%d, wds=%2d, nregs=%d, nfpregs=%d, mode=%s, named=%d)\n\n",
! 	     words, cum->words, cum->nregs, cum->nfpregs, GET_MODE_NAME (mode), named);
  
    cum->words += words;
    cum->nregs -= words;
    cum->regno += words;
+   if (FLOAT_MODE_P (mode))
+     cum->fpregno ++, cum->nfpregs--;
  
    if (cum->nregs <= 0)
      {
        cum->nregs = 0;
        cum->regno = 0;
      }
+   if (cum->nfpregs <= 0)
+     {
+       cum->nfpregs = 0;
+       cum->fpregno = 0;
+     }
  
    return;
  }
*************** function_arg (cum, mode, type, named)
*** 966,972 ****
        /* For now, pass fp/complex values on the stack. */
      default:
        break;
! 
      case BLKmode:
      case DImode:
      case SImode:
--- 1006,1017 ----
        /* For now, pass fp/complex values on the stack. */
      default:
        break;
!     case SFmode:
!     case DFmode:
!     case XFmode:
!       if (cum->nfpregs)
! 	ret = gen_rtx_REG (mode, cum->fpregno);
!       break;
      case BLKmode:
      case DImode:
      case SImode:
*************** function_arg (cum, mode, type, named)
*** 980,987 ****
    if (TARGET_DEBUG_ARG)
      {
        fprintf (stderr,
! 	       "function_arg (size=%d, wds=%2d, nregs=%d, mode=%4s, named=%d",
! 	       words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
  
        if (ret)
  	fprintf (stderr, ", reg=%%e%s", reg_names[ REGNO(ret) ]);
--- 1025,1032 ----
    if (TARGET_DEBUG_ARG)
      {
        fprintf (stderr,
! 	       "function_arg (size=%d, wds=%2d, nregs=%d, nfpregs=%d, mode=%4s, named=%d",
! 	       words, cum->words, cum->nregs, cum->nfpregs, GET_MODE_NAME (mode), named);
  
        if (ret)
  	fprintf (stderr, ", reg=%%e%s", reg_names[ REGNO(ret) ]);
*** i386.h.old	Wed Jul  5 22:58:10 2000
--- i386.h	Wed Jul  5 22:57:57 2000
*************** extern int ix86_arch;
*** 334,340 ****
      N_("Control allocation order of integer registers") },	\
    { "regparm=",		&ix86_regparm_string,			\
      N_("Number of registers used to pass integer arguments") },	\
!   { "i387-regparm=",		&ix86_regparm_string,			\
      N_("Number of registers used to pass integer arguments") },	\
    { "align-loops=",	&ix86_align_loops_string,		\
      N_("Loop code aligned to this power of 2") },		\
--- 334,340 ----
      N_("Control allocation order of integer registers") },	\
    { "regparm=",		&ix86_regparm_string,			\
      N_("Number of registers used to pass integer arguments") },	\
!   { "i387-regparm=",	&ix86_i387_regparm_string,		\
      N_("Number of registers used to pass integer arguments") },	\
    { "align-loops=",	&ix86_align_loops_string,		\
      N_("Loop code aligned to this power of 2") },		\
*************** extern const char *ix86_cpu_string;		/* 
*** 2609,2620 ****
--- 2609,2622 ----
  extern const char *ix86_arch_string;		/* for -march=<xxx> */
  extern const char *ix86_reg_alloc_order;	/* register allocation order */
  extern const char *ix86_regparm_string;		/* # registers to use to pass args */
+ extern const char *ix86_i387_regparm_string;	/* # registers to use to pass args */
  extern const char *ix86_align_loops_string;	/* power of two alignment for loops */
  extern const char *ix86_align_jumps_string;	/* power of two alignment for non-loop jumps */
  extern const char *ix86_align_funcs_string;	/* power of two alignment for functions */
  extern const char *ix86_preferred_stack_boundary_string;/* power of two alignment for stack boundary */
  extern const char *ix86_branch_cost_string;	/* values 1-5: see jump.c */
  extern int ix86_regparm;			/* ix86_regparm_string as a number */
+ extern int ix86_i387_regparm;			/* ix86_regparm_string as a number */
  extern int ix86_align_loops;			/* power of two alignment for loops */
  extern int ix86_align_jumps;			/* power of two alignment for non-loop jumps */
  extern int ix86_align_funcs;			/* power of two alignment for functions */
*** reg-stack.c.old	Wed Jul  5 22:29:26 2000
--- reg-stack.c	Wed Jul  5 22:55:24 2000
*************** convert_regs_entry ()
*** 2302,2307 ****
--- 2302,2309 ----
  {
    int inserted = 0, i;
    edge e;
+   tree parm = DECL_ARGUMENTS (current_function_decl);
+   int incoming_arg [REG_STACK_SIZE];
  
    for (i = n_basic_blocks - 1; i >= 0; --i)
      {
*************** convert_regs_entry ()
*** 2322,2327 ****
--- 2324,2340 ----
  	}
      }
  
+   /* Figure out the arguments passed in stack registers.  */
+   memset (incoming_arg, 0, sizeof (incoming_arg));
+   while (parm)
+     {
+       rtx x = DECL_INCOMING_RTL (parm);
+       if (STACK_REG_P (x))
+ 	incoming_arg[REGNO (x) - FIRST_STACK_REG] = x;
+       parm = TREE_CHAIN (parm);
+     }
+ 
+ 
    /* Load something into each stack register live at function entry. 
       Such live registers can be caused by uninitialized variables or
       functions not returning values on all paths.  In order to keep 
*************** convert_regs_entry ()
*** 2336,2344 ****
        basic_block block = e->dest;
        block_info bi = BLOCK_INFO (block);
        int reg, top = -1;
  
        for (reg = LAST_STACK_REG; reg >= FIRST_STACK_REG; --reg)
! 	if (TEST_HARD_REG_BIT (bi->stack_in.reg_set, reg))
  	  {
  	    rtx init;
  
--- 2349,2364 ----
        basic_block block = e->dest;
        block_info bi = BLOCK_INFO (block);
        int reg, top = -1;
+       int dead_arguments = 0;
+ 
+       /* Put the incoming arguments to the stack.  */
+       for (i = LAST_STACK_REG; i >= FIRST_STACK_REG; i--)
+ 	if (incoming_arg [i - FIRST_STACK_REG])
+ 	  bi->stack_in.reg[++top] = i;
  
        for (reg = LAST_STACK_REG; reg >= FIRST_STACK_REG; --reg)
! 	if (TEST_HARD_REG_BIT (bi->stack_in.reg_set, reg)
! 	    && !incoming_arg [reg - FIRST_STACK_REG])
  	  {
  	    rtx init;
  
*************** convert_regs_entry ()
*** 2350,2357 ****
  	    insert_insn_on_edge (init, e);
  	    inserted = 1;
  	  }
- 
        bi->stack_in.top = top;
      }
  
    return inserted;
--- 2370,2407 ----
  	    insert_insn_on_edge (init, e);
  	    inserted = 1;
  	  }
        bi->stack_in.top = top;
+ 
+       /* Check whether there are any dead arguments that needs
+          to be popped.  */
+       for (i = LAST_STACK_REG; i >= FIRST_STACK_REG; i--)
+ 	if (incoming_arg [i - FIRST_STACK_REG]
+ 	    && !TEST_HARD_REG_BIT (bi->stack_in.reg_set, i))
+ 	  dead_arguments = 1;
+ 
+       if (dead_arguments)
+ 	{
+ 	  rtx seq;
+ 	  rtx after;
+ 	  start_sequence ();
+ 		  
+ 	  /* ??? pop_stack needs some point to emit insns after. 
+ 	     Also needed to keep gen_sequence from returning a 
+ 	     pattern as opposed to a sequence, which would lose
+ 	     REG_DEAD notes.  */
+ 	  after = emit_note (NULL, NOTE_INSN_DELETED);
+ 
+ 	  for (i = LAST_STACK_REG; i >= FIRST_STACK_REG; i--)
+ 	    if (incoming_arg [i - FIRST_STACK_REG]
+ 		&& !TEST_HARD_REG_BIT (bi->stack_in.reg_set,i))
+ 	    after = emit_pop_insn (after, &bi->stack_in,
+ 				   FP_MODE_REG (i, DFmode), EMIT_AFTER);
+ 
+ 	  seq = gen_sequence ();
+ 	  end_sequence ();
+ 	  inserted = 1;
+ 	  insert_insn_on_edge (seq, e);
+ 	}
      }
  
    return inserted;
*** invoke.texi.old	Wed Jul  5 23:34:30 2000
--- invoke.texi	Wed Jul  5 23:35:27 2000
*************** in the following sections.
*** 368,374 ****
  -mieee-fp  -mno-fancy-math-387
  -mno-fp-ret-in-387  -msoft-float  -msvr3-shlib
  -mno-wide-multiply  -mrtd  -malign-double
! -mreg-alloc=@var{list}  -mregparm=@var{num}
  -malign-jumps=@var{num}  -malign-loops=@var{num}
  -malign-functions=@var{num} -mpreferred-stack-boundary=@var{num}
  -mthreads -mno-align-stringops -minline-all-stringops
--- 368,374 ----
  -mieee-fp  -mno-fancy-math-387
  -mno-fp-ret-in-387  -msoft-float  -msvr3-shlib
  -mno-wide-multiply  -mrtd  -malign-double
! -mreg-alloc=@var{list}  -mregparm=@var{num} -mi387-regparm=@var{num}
  -malign-jumps=@var{num}  -malign-loops=@var{num}
  -malign-functions=@var{num} -mpreferred-stack-boundary=@var{num}
  -mthreads -mno-align-stringops -minline-all-stringops
*************** in the following sections.
*** 424,430 ****
  -mdata=@var{data section}  -mrodata=@var{readonly data section}
  
  @emph{TMS320C3x/C4x Options}
! -mcpu=@var{cpu} -mbig -msmall -mregparm -mmemparm
  -mfast-fix -mmpyi -mbk -mti -mdp-isr-reload
  -mrpts=@var{count}  -mrptb -mdb -mloop-unsigned
  -mparallel-insns -mparallel-mpy -mpreserve-float
--- 424,430 ----
  -mdata=@var{data section}  -mrodata=@var{readonly data section}
  
  @emph{TMS320C3x/C4x Options}
! -mcpu=@var{cpu} -mbig -msmall -mregparm -mi386-regparm -mmemparm
  -mfast-fix -mmpyi -mbk -mti -mdp-isr-reload
  -mrpts=@var{count}  -mrptb -mdb -mloop-unsigned
  -mparallel-insns -mparallel-mpy -mpreserve-float
*************** supported letters are: @code{a} allocate
*** 6043,6048 ****
--- 6043,6055 ----
  @item -mregparm=@var{num}
  Control how many registers are used to pass integer arguments.  By
  default, no registers are used to pass arguments, and at most 3
+ registers can be used.  You can control this behavior for a specific
+ function by using the function attribute @samp{regparm}.
+ @xref{Function Attributes}.
+ 
+ @item -mi386-regparm=@var{num}
+ Control how many registers are used to pass floating point arguments.  By
+ default, no registers are used to pass arguments, and at most 8
  registers can be used.  You can control this behavior for a specific
  function by using the function attribute @samp{regparm}.
  @xref{Function Attributes}.
*** extend.texi.old	Wed Jul  5 23:31:29 2000
--- extend.texi	Wed Jul  5 23:35:59 2000
*************** options.  This also allows you to write 
*** 1595,1607 ****
  you wish, without getting infinite recursion if they get compiled with
  @code{-fcheck-memory-usage}.
  
! @item regparm (@var{number})
  @cindex functions that are passed arguments in registers on the 386
  On the Intel 386, the @code{regparm} attribute causes the compiler to
  pass up to @var{number} integer arguments in registers @var{EAX},
  @var{EDX}, and @var{ECX} instead of on the stack.  Functions that take a
  variable number of arguments will continue to be passed all of their
  arguments on the stack.
  
  @item stdcall
  @cindex functions that pop the argument stack on the 386
--- 1595,1611 ----
  you wish, without getting infinite recursion if they get compiled with
  @code{-fcheck-memory-usage}.
  
! @item regparm (@var{number}[,@var{number2}])
  @cindex functions that are passed arguments in registers on the 386
  On the Intel 386, the @code{regparm} attribute causes the compiler to
  pass up to @var{number} integer arguments in registers @var{EAX},
  @var{EDX}, and @var{ECX} instead of on the stack.  Functions that take a
  variable number of arguments will continue to be passed all of their
  arguments on the stack.
+ 
+ The optional @var{number2} parameter is used to control number of
+ floating pointer arguments passed in the i387 register stack instead
+ of the normal stack. I[ to 8 registers can be used.
  
  @item stdcall
  @cindex functions that pop the argument stack on the 386


More information about the Gcc-patches mailing list