[PATCH] 2nd try: Fix PR22347

Richard Guenther rguenther@suse.de
Tue Jul 12 11:26:00 GMT 2005


On Tue, 12 Jul 2005, Richard Guenther wrote:

> On Wed, 6 Jul 2005, Richard Henderson wrote:
> 
> > On Tue, Jul 05, 2005 at 05:14:44PM +0200, Richard Guenther wrote:
> > > I'm lost in the mysteries of expansion of the indirect call, also
> > > ix86_value_regno gets called all over the place, so the "interesting"
> > > call-site is hard to find.
> > 
> > We'll have to change the FUNCTION_VALUE interface to handle this.
> 
> Here's the patch.  Bootstrapped and tested on i686-pc-linux-gnu and
> x86_64-unknown-linux-gnu.

Revised patch which fixes completely PR22347 and more testcases that
did not work before.  Bootstrapped and tested on i686-pc-linux-gnu,
bootstrapped on ia64-unknown-linux-gnu.

Ok for mainline?

Thanks,
Richard.

2005-07-12  Richard Guenther  <rguenther@suse.de>

	PR middle-end/22347
	* Makefile.in (explow.o, reg-stack.o, tree-tailcall.o):
	Depend on target.h.
        * tree-tailcall.c (find_tail_calls): Check if functions have
	compatible attributes.
	* calls.c (expand_call): Pass fntype to hard_function_value.
	(emit_library_call_value_1): Likewise.
	* explow.c: Include target.h.
	(hard_function_value): Take extra argument, the fntype.
	Use new target hook for function_value.
	* expr.h (hard_function_value): Change prototype.
	* function.c (aggregate_value_p): Pass 0 as fntype to
	hard_function_value.
	(assign_parms): Use new target hook for function_value.
	Pass 0 as fntype to hard_function_value.
	(expand_function_end): Likewise.
	* reg-stack.c: Include target.h.
	(stack_result): Use new target hook for function_value.
	* target-def.h: New target hook function_value.
	* target.h: Likewise.
	* targhooks.c (default_function_value): New function.
	* targhooks.h (default_function_value): Declare.
	* config/i386/i386-protos.h (ix86_function_value): Change
	prototype to match new target hook.
	* config/i386/i386.c (ix86_value_regno): Change prototype
	to take extra type argument.
	(TARGET_FUNCTION_VALUE): Define.
	(ix86_function_ok_for_sibcall): Pass extra argument to
	ix86_value_regno.
	(ix86_function_value): Take extra parameter.  Dispatch to
	ix86_value_regno with fndecl/fntype as provided.
	(ix86_value_regno): Handle extra type argument.
	* config/i386/i386.h (FUNCTION_VALUE): No longer define.

	* testsuite/gcc.target/i386/sseregparm-3.c: New testcase.
	* testsuite/gcc.target/i386/sseregparm-4.c: New testcase.
	* testsuite/gcc.target/i386/sseregparm-5.c: New testcase.
	* testsuite/gcc.target/i386/sseregparm-6.c: New testcase.
	* testsuite/gcc.target/i386/sseregparm-7.c: New testcase.


Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1521
diff -c -3 -p -r1.1521 Makefile.in
*** Makefile.in	10 Jul 2005 00:27:44 -0000	1.1521
--- Makefile.in	12 Jul 2005 09:41:12 -0000
*************** tree-cfgcleanup.o : tree-cfgcleanup.c $(
*** 1815,1821 ****
  tree-tailcall.o : tree-tailcall.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
     $(RTL_H) $(TREE_H) $(TM_P_H) function.h $(TM_H) coretypes.h \
     $(TREE_DUMP_H) $(DIAGNOSTIC_H) except.h tree-pass.h $(FLAGS_H) langhooks.h \
!    $(BASIC_BLOCK_H) hard-reg-set.h
  tree-ssa-sink.o : tree-ssa-sink.c $(TREE_FLOW_H) $(CONFIG_H) \
     $(SYSTEM_H) $(TREE_H) $(GGC_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \
     $(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) alloc-pool.h \
--- 1815,1821 ----
  tree-tailcall.o : tree-tailcall.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
     $(RTL_H) $(TREE_H) $(TM_P_H) function.h $(TM_H) coretypes.h \
     $(TREE_DUMP_H) $(DIAGNOSTIC_H) except.h tree-pass.h $(FLAGS_H) langhooks.h \
!    $(BASIC_BLOCK_H) hard-reg-set.h target.h
  tree-ssa-sink.o : tree-ssa-sink.c $(TREE_FLOW_H) $(CONFIG_H) \
     $(SYSTEM_H) $(TREE_H) $(GGC_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \
     $(TM_H) coretypes.h $(TREE_DUMP_H) tree-pass.h $(FLAGS_H) alloc-pool.h \
*************** expmed.o : expmed.c $(CONFIG_H) $(SYSTEM
*** 2079,2085 ****
     toplev.h $(TM_P_H) langhooks.h
  explow.o : explow.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
     $(FLAGS_H) hard-reg-set.h insn-config.h $(EXPR_H) $(OPTABS_H) $(RECOG_H) \
!    toplev.h function.h $(GGC_H) $(TM_P_H) langhooks.h gt-explow.h
  optabs.o : optabs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
     $(TREE_H) $(FLAGS_H) insn-config.h $(EXPR_H) $(OPTABS_H) libfuncs.h \
     $(RECOG_H) reload.h toplev.h $(GGC_H) real.h $(TM_P_H) except.h \
--- 2079,2085 ----
     toplev.h $(TM_P_H) langhooks.h
  explow.o : explow.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
     $(FLAGS_H) hard-reg-set.h insn-config.h $(EXPR_H) $(OPTABS_H) $(RECOG_H) \
!    toplev.h function.h $(GGC_H) $(TM_P_H) langhooks.h gt-explow.h target.h
  optabs.o : optabs.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
     $(TREE_H) $(FLAGS_H) insn-config.h $(EXPR_H) $(OPTABS_H) libfuncs.h \
     $(RECOG_H) reload.h toplev.h $(GGC_H) real.h $(TM_P_H) except.h \
*************** recog.o : recog.c $(CONFIG_H) $(SYSTEM_H
*** 2391,2397 ****
  reg-stack.o : reg-stack.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
     $(RTL_H) $(TREE_H) $(RECOG_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
     insn-config.h toplev.h reload.h function.h $(TM_P_H) $(GGC_H) \
!    gt-reg-stack.h $(BASIC_BLOCK_H) output.h $(VARRAY_H) timevar.h tree-pass.h
  sreal.o: sreal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) sreal.h
  predict.o: predict.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
     $(TREE_H) $(FLAGS_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) \
--- 2391,2398 ----
  reg-stack.o : reg-stack.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
     $(RTL_H) $(TREE_H) $(RECOG_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) \
     insn-config.h toplev.h reload.h function.h $(TM_P_H) $(GGC_H) \
!    gt-reg-stack.h $(BASIC_BLOCK_H) output.h $(VARRAY_H) timevar.h tree-pass.h \
!    target.h
  sreal.o: sreal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) sreal.h
  predict.o: predict.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
     $(TREE_H) $(FLAGS_H) insn-config.h $(BASIC_BLOCK_H) $(REGS_H) \
Index: calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.392
diff -c -3 -p -r1.392 calls.c
*** calls.c	26 Jun 2005 05:27:05 -0000	1.392
--- calls.c	12 Jul 2005 09:41:13 -0000
*************** expand_call (tree exp, rtx target, int i
*** 2517,2525 ****
  	{
  	  if (pcc_struct_value)
  	    valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)),
! 					  fndecl, (pass == 0));
  	  else
! 	    valreg = hard_function_value (TREE_TYPE (exp), fndecl, (pass == 0));
  	}
  
        /* Precompute all register parameters.  It isn't safe to compute anything
--- 2517,2526 ----
  	{
  	  if (pcc_struct_value)
  	    valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)),
! 					  fndecl, NULL, (pass == 0));
  	  else
! 	    valreg = hard_function_value (TREE_TYPE (exp), fndecl, fntype,
! 					  (pass == 0));
  	}
  
        /* Precompute all register parameters.  It isn't safe to compute anything
*************** emit_library_call_value_1 (int retval, r
*** 3266,3272 ****
  	{
  #ifdef PCC_STATIC_STRUCT_RETURN
  	  rtx pointer_reg
! 	    = hard_function_value (build_pointer_type (tfom), 0, 0);
  	  mem_value = gen_rtx_MEM (outmode, pointer_reg);
  	  pcc_struct_value = 1;
  	  if (value == 0)
--- 3267,3273 ----
  	{
  #ifdef PCC_STATIC_STRUCT_RETURN
  	  rtx pointer_reg
! 	    = hard_function_value (build_pointer_type (tfom), 0, 0, 0);
  	  mem_value = gen_rtx_MEM (outmode, pointer_reg);
  	  pcc_struct_value = 1;
  	  if (value == 0)
Index: explow.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/explow.c,v
retrieving revision 1.147
diff -c -3 -p -r1.147 explow.c
*** explow.c	25 Jun 2005 01:59:47 -0000	1.147
--- explow.c	12 Jul 2005 09:41:13 -0000
*************** Software Foundation, 51 Franklin Street,
*** 37,42 ****
--- 37,43 ----
  #include "ggc.h"
  #include "recog.h"
  #include "langhooks.h"
+ #include "target.h"
  
  static rtx break_out_memory_refs (rtx);
  static void emit_stack_probe (rtx);
*************** probe_stack_range (HOST_WIDE_INT first, 
*** 1405,1428 ****
  /* Return an rtx representing the register or memory location
     in which a scalar value of data type VALTYPE
     was returned by a function call to function FUNC.
!    FUNC is a FUNCTION_DECL node if the precise function is known,
!    otherwise 0.
     OUTGOING is 1 if on a machine with register windows this function
     should return the register in which the function will put its result
     and 0 otherwise.  */
  
  rtx
! hard_function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
  		     int outgoing ATTRIBUTE_UNUSED)
  {
    rtx val;
  
! #ifdef FUNCTION_OUTGOING_VALUE
!   if (outgoing)
!     val = FUNCTION_OUTGOING_VALUE (valtype, func);
!   else
! #endif
!     val = FUNCTION_VALUE (valtype, func);
  
    if (REG_P (val)
        && GET_MODE (val) == BLKmode)
--- 1406,1424 ----
  /* Return an rtx representing the register or memory location
     in which a scalar value of data type VALTYPE
     was returned by a function call to function FUNC.
!    FUNC is a FUNCTION_DECL, FNTYPE a FUNCTION_TYPE node if the precise
!    function is known, otherwise 0.
     OUTGOING is 1 if on a machine with register windows this function
     should return the register in which the function will put its result
     and 0 otherwise.  */
  
  rtx
! hard_function_value (tree valtype, tree func, tree fntype,
  		     int outgoing ATTRIBUTE_UNUSED)
  {
    rtx val;
  
!   val = targetm.calls.function_value (valtype, func ? func : fntype, outgoing);
  
    if (REG_P (val)
        && GET_MODE (val) == BLKmode)
Index: expr.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.h,v
retrieving revision 1.191
diff -c -3 -p -r1.191 expr.h
*** expr.h	28 Jun 2005 19:55:52 -0000	1.191
--- expr.h	12 Jul 2005 09:41:13 -0000
*************** extern HOST_WIDE_INT int_expr_size (tree
*** 550,556 ****
  
  /* Return an rtx that refers to the value returned by a function
     in its original home.  This becomes invalid if any more code is emitted.  */
! extern rtx hard_function_value (tree, tree, int);
  
  extern rtx prepare_call_address (rtx, rtx, rtx *, int, int);
  
--- 550,556 ----
  
  /* Return an rtx that refers to the value returned by a function
     in its original home.  This becomes invalid if any more code is emitted.  */
! extern rtx hard_function_value (tree, tree, tree, int);
  
  extern rtx prepare_call_address (rtx, rtx, rtx *, int, int);
  
Index: function.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/function.c,v
retrieving revision 1.635
diff -c -3 -p -r1.635 function.c
*** function.c	7 Jul 2005 21:04:31 -0000	1.635
--- function.c	12 Jul 2005 09:41:14 -0000
*************** aggregate_value_p (tree exp, tree fntype
*** 1732,1738 ****
      return 1;
    /* Make sure we have suitable call-clobbered regs to return
       the value in; if not, we must return it in memory.  */
!   reg = hard_function_value (type, 0, 0);
  
    /* If we have something other than a REG (e.g. a PARALLEL), then assume
       it is OK.  */
--- 1732,1738 ----
      return 1;
    /* Make sure we have suitable call-clobbered regs to return
       the value in; if not, we must return it in memory.  */
!   reg = hard_function_value (type, 0, fntype, 0);
  
    /* If we have something other than a REG (e.g. a PARALLEL), then assume
       it is OK.  */
*************** assign_parms (tree fndecl)
*** 3055,3067 ****
  	{
  	  rtx real_decl_rtl;
  
! #ifdef FUNCTION_OUTGOING_VALUE
! 	  real_decl_rtl = FUNCTION_OUTGOING_VALUE (TREE_TYPE (decl_result),
! 						   fndecl);
! #else
! 	  real_decl_rtl = FUNCTION_VALUE (TREE_TYPE (decl_result),
! 					  fndecl);
! #endif
  	  REG_FUNCTION_VALUE_P (real_decl_rtl) = 1;
  	  /* The delay slot scheduler assumes that current_function_return_rtx
  	     holds the hard register containing the return value, not a
--- 3055,3062 ----
  	{
  	  rtx real_decl_rtl;
  
! 	  real_decl_rtl = targetm.calls.function_value (TREE_TYPE (decl_result),
! 							fndecl, true);
  	  REG_FUNCTION_VALUE_P (real_decl_rtl) = 1;
  	  /* The delay slot scheduler assumes that current_function_return_rtx
  	     holds the hard register containing the return value, not a
*************** expand_function_start (tree subr)
*** 4149,4155 ****
  	  /* In order to figure out what mode to use for the pseudo, we
  	     figure out what the mode of the eventual return register will
  	     actually be, and use that.  */
! 	  rtx hard_reg = hard_function_value (return_type, subr, 1);
  
  	  /* Structures that are returned in registers are not
  	     aggregate_value_p, so we may see a PARALLEL or a REG.  */
--- 4144,4150 ----
  	  /* In order to figure out what mode to use for the pseudo, we
  	     figure out what the mode of the eventual return register will
  	     actually be, and use that.  */
! 	  rtx hard_reg = hard_function_value (return_type, subr, 0, 1);
  
  	  /* Structures that are returned in registers are not
  	     aggregate_value_p, so we may see a PARALLEL or a REG.  */
*************** expand_function_end (void)
*** 4499,4511 ****
        else
  	value_address = XEXP (value_address, 0);
  
! #ifdef FUNCTION_OUTGOING_VALUE
!       outgoing = FUNCTION_OUTGOING_VALUE (build_pointer_type (type),
! 					  current_function_decl);
! #else
!       outgoing = FUNCTION_VALUE (build_pointer_type (type),
! 				 current_function_decl);
! #endif 
  
        /* Mark this as a function return value so integrate will delete the
  	 assignment and USE below when inlining this function.  */
--- 4494,4501 ----
        else
  	value_address = XEXP (value_address, 0);
  
!       outgoing = targetm.calls.function_value (build_pointer_type (type),
! 					       current_function_decl, true);
  
        /* Mark this as a function return value so integrate will delete the
  	 assignment and USE below when inlining this function.  */
Index: reg-stack.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reg-stack.c,v
retrieving revision 1.187
diff -c -3 -p -r1.187 reg-stack.c
*** reg-stack.c	5 Jul 2005 16:20:11 -0000	1.187
--- reg-stack.c	12 Jul 2005 09:41:14 -0000
***************
*** 172,177 ****
--- 172,178 ----
  #include "ggc.h"
  #include "timevar.h"
  #include "tree-pass.h"
+ #include "target.h"
  
  /* We use this array to cache info about insns, because otherwise we
     spend too much time in stack_regs_mentioned_p.
*************** stack_result (tree decl)
*** 667,680 ****
  
    result = DECL_RTL_IF_SET (DECL_RESULT (decl));
    if (result != 0)
!     {
! #ifdef FUNCTION_OUTGOING_VALUE
!       result
! 	= FUNCTION_OUTGOING_VALUE (TREE_TYPE (DECL_RESULT (decl)), decl);
! #else
!       result = FUNCTION_VALUE (TREE_TYPE (DECL_RESULT (decl)), decl);
! #endif
!     }
  
    return result != 0 && STACK_REG_P (result) ? result : 0;
  }
--- 668,675 ----
  
    result = DECL_RTL_IF_SET (DECL_RESULT (decl));
    if (result != 0)
!     result = targetm.calls.function_value (TREE_TYPE (DECL_RESULT (decl)),
! 					   decl, true);
  
    return result != 0 && STACK_REG_P (result) ? result : 0;
  }
Index: target-def.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/target-def.h,v
retrieving revision 1.131
diff -c -3 -p -r1.131 target-def.h
*** target-def.h	7 Jul 2005 11:48:13 -0000	1.131
--- target-def.h	12 Jul 2005 09:41:14 -0000
*************** Foundation, 51 Franklin Street, Fifth Fl
*** 438,443 ****
--- 438,445 ----
  #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_false
  #define TARGET_ARG_PARTIAL_BYTES hook_int_CUMULATIVE_ARGS_mode_tree_bool_0
  
+ #define TARGET_FUNCTION_VALUE default_function_value
+ 
  #define TARGET_CALLS {						\
     TARGET_PROMOTE_FUNCTION_ARGS,				\
     TARGET_PROMOTE_FUNCTION_RETURN,				\
*************** Foundation, 51 Franklin Street, Fifth Fl
*** 454,460 ****
     TARGET_MUST_PASS_IN_STACK,					\
     TARGET_CALLEE_COPIES,					\
     TARGET_ARG_PARTIAL_BYTES,					\
!    TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN			\
     }
  
  #ifndef TARGET_UNWIND_TABLES_DEFAULT
--- 456,463 ----
     TARGET_MUST_PASS_IN_STACK,					\
     TARGET_CALLEE_COPIES,					\
     TARGET_ARG_PARTIAL_BYTES,					\
!    TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN,			\
!    TARGET_FUNCTION_VALUE					\
     }
  
  #ifndef TARGET_UNWIND_TABLES_DEFAULT
Index: target.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/target.h,v
retrieving revision 1.143
diff -c -3 -p -r1.143 target.h
*** target.h	7 Jul 2005 11:48:13 -0000	1.143
--- target.h	12 Jul 2005 09:41:14 -0000
*************** struct gcc_target
*** 603,608 ****
--- 603,612 ----
         is not allowed for this 'val' argument; NULL otherwise. */
      const char *(*invalid_arg_for_unprototyped_fn) (tree typelist, 
  					     	    tree funcdecl, tree val);
+ 
+     /* FUNCTION_VALUE */
+     rtx (*function_value) (tree ret_type, tree fn_decl_or_type,
+ 			   bool outgoing);
    } calls;
  
    /* Return the diagnostic message string if conversion from FROMTYPE
Index: targhooks.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/targhooks.c,v
retrieving revision 2.45
diff -c -3 -p -r2.45 targhooks.c
*** targhooks.c	7 Jul 2005 11:48:13 -0000	2.45
--- targhooks.c	12 Jul 2005 11:11:59 -0000
*************** hook_bool_rtx_commutative_p (rtx x, int 
*** 417,420 ****
--- 417,442 ----
    return COMMUTATIVE_P (x);
  }
  
+ rtx
+ default_function_value (tree ret_type ATTRIBUTE_UNUSED,
+ 			tree fn_decl_or_type,
+ 			bool outgoing ATTRIBUTE_UNUSED)
+ {
+   /* The old interface doesn't handle receiving the function type.  */
+   if (fn_decl_or_type
+       && !DECL_P (fn_decl_or_type))
+     fn_decl_or_type = NULL;
+ 
+ #ifdef FUNCTION_OUTGOING_VALUE
+   if (outgoing)
+     return FUNCTION_OUTGOING_VALUE (ret_type, fn_decl_or_type);
+ #endif
+ 
+ #ifdef FUNCTION_VALUE
+   return FUNCTION_VALUE (ret_type, fn_decl_or_type);
+ #else
+   return NULL_RTX;
+ #endif
+ }
+ 
  #include "gt-targhooks.h"
Index: targhooks.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/targhooks.h,v
retrieving revision 2.32
diff -c -3 -p -r2.32 targhooks.h
*** targhooks.h	7 Jul 2005 11:48:13 -0000	2.32
--- targhooks.h	12 Jul 2005 09:41:14 -0000
*************** extern int hook_int_CUMULATIVE_ARGS_mode
*** 67,69 ****
--- 67,71 ----
  extern const char *hook_invalid_arg_for_unprototyped_fn
    (tree, tree, tree);
  extern bool hook_bool_rtx_commutative_p (rtx, int);
+ extern rtx default_function_value (tree, tree, bool);
+ 
Index: tree-tailcall.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-tailcall.c,v
retrieving revision 2.44
diff -c -3 -p -r2.44 tree-tailcall.c
*** tree-tailcall.c	30 Jun 2005 22:18:36 -0000	2.44
--- tree-tailcall.c	12 Jul 2005 09:41:14 -0000
*************** Boston, MA 02110-1301, USA.  */
*** 35,40 ****
--- 35,41 ----
  #include "tree-pass.h"
  #include "flags.h"
  #include "langhooks.h"
+ #include "target.h"
  
  /* The file implements the tail recursion elimination.  It is also used to
     analyze the tail calls in general, passing the results to the rtl level
*************** find_tail_calls (basic_block bb, struct 
*** 380,386 ****
    bool tail_recursion;
    struct tailcall *nw;
    edge e;
!   tree m, a;
    basic_block abb;
    stmt_ann_t ann;
  
--- 381,387 ----
    bool tail_recursion;
    struct tailcall *nw;
    edge e;
!   tree m, a, fntype;
    basic_block abb;
    stmt_ann_t ann;
  
*************** find_tail_calls (basic_block bb, struct 
*** 432,437 ****
--- 433,441 ----
    /* We found the call, check whether it is suitable.  */
    tail_recursion = false;
    func = get_callee_fndecl (call);
+   fntype = TREE_TYPE (TREE_OPERAND (call, 0));
+   if (POINTER_TYPE_P (fntype))
+     fntype = TREE_TYPE (fntype);
    if (func == current_function_decl)
      {
        for (param = DECL_ARGUMENTS (func), args = TREE_OPERAND (call, 1);
*************** find_tail_calls (basic_block bb, struct 
*** 465,470 ****
--- 469,479 ----
  	tail_recursion = true;
      }
  
+   /* Only optimize calls which have compatible function type attributes.  */
+   if (targetm.comp_type_attributes (TREE_TYPE (current_function_decl),
+ 				    fntype) != 1)
+     return;
+ 
    /* Now check the statements after the call.  None of them has virtual
       operands, so they may only depend on the call through its return
       value.  The return value should also be dependent on each of them,
Index: config/i386/i386-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386-protos.h,v
retrieving revision 1.143
diff -c -3 -p -r1.143 i386-protos.h
*** config/i386/i386-protos.h	29 Jun 2005 17:27:16 -0000	1.143
--- config/i386/i386-protos.h	12 Jul 2005 09:41:15 -0000
*************** extern void init_cumulative_args (CUMULA
*** 206,212 ****
  extern rtx function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
  extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode,
  				  tree, int);
! extern rtx ix86_function_value (tree, tree);
  #endif
  
  #endif
--- 206,212 ----
  extern rtx function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
  extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode,
  				  tree, int);
! extern rtx ix86_function_value (tree, tree, bool);
  #endif
  
  #endif
Index: config/i386/i386.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v
retrieving revision 1.841
diff -c -3 -p -r1.841 i386.c
*** config/i386/i386.c	11 Jul 2005 09:35:16 -0000	1.841
--- config/i386/i386.c	12 Jul 2005 09:41:18 -0000
*************** static int ix86_function_regparm (tree, 
*** 891,897 ****
  const struct attribute_spec ix86_attribute_table[];
  static bool ix86_function_ok_for_sibcall (tree, tree);
  static tree ix86_handle_cconv_attribute (tree *, tree, tree, int, bool *);
! static int ix86_value_regno (enum machine_mode, tree);
  static bool contains_128bit_aligned_vector_p (tree);
  static rtx ix86_struct_value_rtx (tree, int);
  static bool ix86_ms_bitfield_layout_p (tree);
--- 891,897 ----
  const struct attribute_spec ix86_attribute_table[];
  static bool ix86_function_ok_for_sibcall (tree, tree);
  static tree ix86_handle_cconv_attribute (tree *, tree, tree, int, bool *);
! static int ix86_value_regno (enum machine_mode, tree, tree);
  static bool contains_128bit_aligned_vector_p (tree);
  static rtx ix86_struct_value_rtx (tree, int);
  static bool ix86_ms_bitfield_layout_p (tree);
*************** static void init_ext_80387_constants (vo
*** 1085,1090 ****
--- 1085,1093 ----
  #undef TARGET_STACK_PROTECT_FAIL
  #define TARGET_STACK_PROTECT_FAIL ix86_stack_protect_fail
  
+ #undef TARGET_FUNCTION_VALUE
+ #define TARGET_FUNCTION_VALUE ix86_function_value
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  
*************** ix86_function_ok_for_sibcall (tree decl,
*** 1722,1730 ****
       function that does or, conversely, from a function that does return
       a float to a function that doesn't; the necessary stack adjustment
       would not be executed.  */
!   if (STACK_REG_P (ix86_function_value (TREE_TYPE (exp), func))
        != STACK_REG_P (ix86_function_value (TREE_TYPE (DECL_RESULT (cfun->decl)),
! 					   cfun->decl)))
      return false;
  
    /* If this call is indirect, we'll need to be able to use a call-clobbered
--- 1725,1733 ----
       function that does or, conversely, from a function that does return
       a float to a function that doesn't; the necessary stack adjustment
       would not be executed.  */
!   if (STACK_REG_P (ix86_function_value (TREE_TYPE (exp), func, false))
        != STACK_REG_P (ix86_function_value (TREE_TYPE (DECL_RESULT (cfun->decl)),
! 					   cfun->decl, false)))
      return false;
  
    /* If this call is indirect, we'll need to be able to use a call-clobbered
*************** ix86_function_value_regno_p (int regno)
*** 3189,3195 ****
     If the precise function being called is known, FUNC is its FUNCTION_DECL;
     otherwise, FUNC is 0.  */
  rtx
! ix86_function_value (tree valtype, tree func)
  {
    enum machine_mode natmode = type_natural_mode (valtype);
  
--- 3192,3199 ----
     If the precise function being called is known, FUNC is its FUNCTION_DECL;
     otherwise, FUNC is 0.  */
  rtx
! ix86_function_value (tree valtype, tree fntype_or_decl,
! 		     bool outgoing ATTRIBUTE_UNUSED)
  {
    enum machine_mode natmode = type_natural_mode (valtype);
  
*************** ix86_function_value (tree valtype, tree 
*** 3205,3211 ****
        return ret;
      }
    else
!     return gen_rtx_REG (TYPE_MODE (valtype), ix86_value_regno (natmode, func));
  }
  
  /* Return false iff type is returned in memory.  */
--- 3209,3223 ----
        return ret;
      }
    else
!     {
!       tree fn = NULL_TREE, fntype;
!       if (fntype_or_decl
! 	  && DECL_P (fntype_or_decl))
!         fn = fntype_or_decl;
!       fntype = fn ? TREE_TYPE (fn) : fntype_or_decl;
!       return gen_rtx_REG (TYPE_MODE (valtype),
! 			  ix86_value_regno (natmode, fn, fntype));
!     }
  }
  
  /* Return false iff type is returned in memory.  */
*************** ix86_libcall_value (enum machine_mode mo
*** 3321,3333 ****
  	}
      }
    else
!     return gen_rtx_REG (mode, ix86_value_regno (mode, NULL));
  }
  
  /* Given a mode, return the register to use for a return value.  */
  
  static int
! ix86_value_regno (enum machine_mode mode, tree func)
  {
    gcc_assert (!TARGET_64BIT);
  
--- 3333,3345 ----
  	}
      }
    else
!     return gen_rtx_REG (mode, ix86_value_regno (mode, NULL, NULL));
  }
  
  /* Given a mode, return the register to use for a return value.  */
  
  static int
! ix86_value_regno (enum machine_mode mode, tree func, tree fntype)
  {
    gcc_assert (!TARGET_64BIT);
  
*************** ix86_value_regno (enum machine_mode mode
*** 3347,3355 ****
  
    /* Floating point return values in %st(0), except for local functions when
       SSE math is enabled or for functions with sseregparm attribute.  */
!   if (func && (mode == SFmode || mode == DFmode))
      {
!       int sse_level = ix86_function_sseregparm (TREE_TYPE (func), func);
        if ((sse_level >= 1 && mode == SFmode)
  	  || (sse_level == 2 && mode == DFmode))
          return FIRST_SSE_REG;
--- 3359,3368 ----
  
    /* Floating point return values in %st(0), except for local functions when
       SSE math is enabled or for functions with sseregparm attribute.  */
!   if ((func || fntype)
!       && (mode == SFmode || mode == DFmode))
      {
!       int sse_level = ix86_function_sseregparm (fntype, func);
        if ((sse_level >= 1 && mode == SFmode)
  	  || (sse_level == 2 && mode == DFmode))
          return FIRST_SSE_REG;
Index: config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.h,v
retrieving revision 1.440
diff -c -3 -p -r1.440 i386.h
*** config/i386/i386.h	26 Jun 2005 05:18:34 -0000	1.440
--- config/i386/i386.h	12 Jul 2005 09:41:18 -0000
*************** enum reg_class
*** 1433,1445 ****
  #define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) \
    ix86_return_pops_args ((FUNDECL), (FUNTYPE), (SIZE))
  
- /* Define how to find the value returned by a function.
-    VALTYPE is the data type of the value (as a tree).
-    If the precise function being called is known, FUNC is its FUNCTION_DECL;
-    otherwise, FUNC is 0.  */
- #define FUNCTION_VALUE(VALTYPE, FUNC)  \
-    ix86_function_value (VALTYPE, FUNC)
- 
  #define FUNCTION_VALUE_REGNO_P(N) \
    ix86_function_value_regno_p (N)
  
--- 1433,1438 ----

/* { dg-do compile } */
/* { dg-options "-msse2 -O2" } */
/* { dg-require-effective-target ilp32 } */

/* Make sure we know that mysinfp returns in %xmm0.  */

double __attribute__((sseregparm)) mysin(double x);
double __attribute__((sseregparm)) (*mysinfp)(double) = mysin;
double bar(double x)
{
  return 1.0+mysinfp(x);
}

/* { dg-final { scan-assembler "fldl" } } */

/* { dg-do compile } */
/* { dg-options "-msse2 -O2" } */
/* { dg-require-effective-target ilp32 } */

/* Make sure we know that mysinfp returns in %xmm0.  */

double __attribute__((sseregparm)) mysin(double x);
double __attribute__((sseregparm)) (*mysinfp)(double) = mysin;
double bar(double x)
{
  return mysinfp(x);
}

/* { dg-final { scan-assembler "fldl" } } */

/* { dg-do compile } */
/* { dg-options "-msse2 -O2" } */
/* { dg-require-effective-target ilp32 } */

/* Make sure we know that mysinfp returns in %xmm0.  */

double __attribute__((sseregparm)) mysin(void);
double __attribute__((sseregparm)) (*mysinfp)(void) = mysin;
double bar(double x)
{
  return mysinfp();
}

/* { dg-final { scan-assembler "fldl" } } */

/* { dg-do compile } */
/* { dg-options "-msse2 -O2" } */
/* { dg-require-effective-target ilp32 } */

/* Make sure we know that mysinfp returns in %xmm0.  */

double __attribute__((sseregparm)) mysin(double x);
double bar(double x)
{
  return mysin(x);
}

/* { dg-final { scan-assembler "fldl" } } */

/* { dg-do compile } */
/* { dg-options "-msse2 -O2" } */
/* { dg-require-effective-target ilp32 } */

/* Make sure we know that mysinfp returns in %xmm0.  */

double __attribute__((sseregparm)) mysin(void);
double bar(double x)
{
  return mysin();
}

/* { dg-final { scan-assembler "fldl" } } */



More information about the Gcc-patches mailing list