PATCH: Thunk infrastructure improvement on ARM branch

Mark Mitchell mark@codesourcery.com
Wed Nov 5 23:18:00 GMT 2003


In order to fix a thunk problem in Thumb mode, we need to stop using
current_function_is_thunk both for real thunks (as generated with
asm_output_mi_thunk) and for pseudo-thunks (which are generated as
ordinary trees, but have funny semantics in that they do not copy
arguments passed by value when transferring control to the thunked-to
function).

After this patch, current_function_is_thunk means that we are in the
asm_output_mi_thunk case.

Tested on powerpc-none-eabisim (*not* arm-none-elf) and
i686-pc-linux-gnu and commited on the csl-arm-branch.  (There is no
alpha simulator, so I did not test alpha, which is the other platform
conceivably impacted by this change.)  Once the thunk bug is actually
fixed, we may move this patch back to the mainline, but there's no
point in doing that until the underlying bug is actually fixed.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2003-11-05  Mark Mitchell  <mark@codesourcery.com>

	* calls.c (initialize_argument_information): Add CALL_FROM_THUNK_P
	parameter.  Use it instead of current_function_is_thunk.
	* function.h (struct function): Update documentation for is_thunk.
	* tree.h (CALL_FROM_THUNK_P): New macro.
	* config/alpha/alpha.c (alpha_sa_mask): Do not check
	no_new_pseudos when testing current_function_is_thunk.
	* config/rs6000/rs6000.c (rs6000_ra_ever_killed): Likeiwse.

2003-11-05  Mark Mitchell  <mark@codesourcery.com>

	* decl.c (cxx_push_function_context): Do not set
	current_function_is_thunk.
	* method.c (use_thunk): Set CALL_FROM_THUNK on the call to the
	actual function.

Index: calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.304
diff -c -5 -p -r1.304 calls.c
*** calls.c	7 Oct 2003 19:48:17 -0000	1.304
--- calls.c	5 Nov 2003 09:54:03 -0000
*************** static int finalize_must_preallocate (in
*** 131,141 ****
  static void precompute_arguments (int, int, struct arg_data *);
  static int compute_argument_block_size (int, struct args_size *, int);
  static void initialize_argument_information (int, struct arg_data *,
  					     struct args_size *, int, tree,
  					     tree, CUMULATIVE_ARGS *, int,
! 					     rtx *, int *, int *, int *);
  static void compute_argument_addresses (struct arg_data *, rtx, int);
  static rtx rtx_for_function_call (tree, tree);
  static void load_register_parameters (struct arg_data *, int, rtx *, int,
  				      int, int *);
  static rtx emit_library_call_value_1 (int, rtx, rtx, enum libcall_type,
--- 131,142 ----
  static void precompute_arguments (int, int, struct arg_data *);
  static int compute_argument_block_size (int, struct args_size *, int);
  static void initialize_argument_information (int, struct arg_data *,
  					     struct args_size *, int, tree,
  					     tree, CUMULATIVE_ARGS *, int,
! 					     rtx *, int *, int *, int *,
! 					     bool);
  static void compute_argument_addresses (struct arg_data *, rtx, int);
  static rtx rtx_for_function_call (tree, tree);
  static void load_register_parameters (struct arg_data *, int, rtx *, int,
  				      int, int *);
  static rtx emit_library_call_value_1 (int, rtx, rtx, enum libcall_type,
*************** store_unaligned_arguments_into_pseudos (
*** 998,1019 ****
  
     OLD_STACK_LEVEL is a pointer to an rtx which olds the old stack level
     and may be modified by this routine.
  
     OLD_PENDING_ADJ, MUST_PREALLOCATE and FLAGS are pointers to integer
!    flags which may may be modified by this routine.  */
  
  static void
  initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
  				 struct arg_data *args,
  				 struct args_size *args_size,
  				 int n_named_args ATTRIBUTE_UNUSED,
  				 tree actparms, tree fndecl,
  				 CUMULATIVE_ARGS *args_so_far,
  				 int reg_parm_stack_space,
  				 rtx *old_stack_level, int *old_pending_adj,
! 				 int *must_preallocate, int *ecf_flags)
  {
    /* 1 if scanning parms front to back, -1 if scanning back to front.  */
    int inc;
  
    /* Count arg position in order args appear.  */
--- 999,1024 ----
  
     OLD_STACK_LEVEL is a pointer to an rtx which olds the old stack level
     and may be modified by this routine.
  
     OLD_PENDING_ADJ, MUST_PREALLOCATE and FLAGS are pointers to integer
!    flags which may may be modified by this routine. 
! 
!    CALL_FROM_THUNK_P is true if this call is the jump from a thunk to
!    the thunked-to function.  */
  
  static void
  initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
  				 struct arg_data *args,
  				 struct args_size *args_size,
  				 int n_named_args ATTRIBUTE_UNUSED,
  				 tree actparms, tree fndecl,
  				 CUMULATIVE_ARGS *args_so_far,
  				 int reg_parm_stack_space,
  				 rtx *old_stack_level, int *old_pending_adj,
! 				 int *must_preallocate, int *ecf_flags,
! 				 bool call_from_thunk_p)
  {
    /* 1 if scanning parms front to back, -1 if scanning back to front.  */
    int inc;
  
    /* Count arg position in order args appear.  */
*************** initialize_argument_information (int num
*** 1082,1092 ****
  #endif
  	  )
  	{
  	  /* If we're compiling a thunk, pass through invisible
               references instead of making a copy.  */
! 	  if (current_function_is_thunk
  #ifdef FUNCTION_ARG_CALLEE_COPIES
  	      || (FUNCTION_ARG_CALLEE_COPIES (*args_so_far, TYPE_MODE (type),
  					     type, argpos < n_named_args)
  		  /* If it's in a register, we must make a copy of it too.  */
  		  /* ??? Is this a sufficient test?  Is there a better one? */
--- 1087,1097 ----
  #endif
  	  )
  	{
  	  /* If we're compiling a thunk, pass through invisible
               references instead of making a copy.  */
! 	  if (call_from_thunk_p
  #ifdef FUNCTION_ARG_CALLEE_COPIES
  	      || (FUNCTION_ARG_CALLEE_COPIES (*args_so_far, TYPE_MODE (type),
  					     type, argpos < n_named_args)
  		  /* If it's in a register, we must make a copy of it too.  */
  		  /* ??? Is this a sufficient test?  Is there a better one? */
*************** expand_call (tree exp, rtx target, int i
*** 2392,2402 ****
       arguments into ARGS_SIZE, etc.  */
    initialize_argument_information (num_actuals, args, &args_size,
  				   n_named_args, actparms, fndecl,
  				   &args_so_far, reg_parm_stack_space,
  				   &old_stack_level, &old_pending_adj,
! 				   &must_preallocate, &flags);
  
    if (args_size.var)
      {
        /* If this function requires a variable-sized argument list, don't
  	 try to make a cse'able block for this call.  We may be able to
--- 2397,2408 ----
       arguments into ARGS_SIZE, etc.  */
    initialize_argument_information (num_actuals, args, &args_size,
  				   n_named_args, actparms, fndecl,
  				   &args_so_far, reg_parm_stack_space,
  				   &old_stack_level, &old_pending_adj,
! 				   &must_preallocate, &flags,
! 				   CALL_FROM_THUNK_P (exp));
  
    if (args_size.var)
      {
        /* If this function requires a variable-sized argument list, don't
  	 try to make a cse'able block for this call.  We may be able to
Index: function.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/function.h,v
retrieving revision 1.103
diff -c -5 -p -r1.103 function.h
*** function.h	25 Sep 2003 01:25:50 -0000	1.103
--- function.h	5 Nov 2003 09:54:03 -0000
*************** struct function GTY(())
*** 453,465 ****
    unsigned int contains_functions : 1;
  
    /* Nonzero if the function being compiled issues a computed jump.  */
    unsigned int has_computed_jump : 1;
  
!   /* Nonzero if the current function is a thunk (a lightweight function that
!      just adjusts one of its arguments and forwards to another function), so
!      we should try to cut corners where we can.  */
    unsigned int is_thunk : 1;
  
    /* This bit is used by the exception handling logic.  It is set if all
       calls (if any) are sibling calls.  Such functions do not have to
       have EH tables generated, as they cannot throw.  A call to such a
--- 453,466 ----
    unsigned int contains_functions : 1;
  
    /* Nonzero if the function being compiled issues a computed jump.  */
    unsigned int has_computed_jump : 1;
  
!   /* Nonzero if the current function is a thunk, i.e., a lightweight
!      function implemented by the output_mi_thunk hook) that just
!      adjusts one of its arguments and forwards to another
!      function.  */
    unsigned int is_thunk : 1;
  
    /* This bit is used by the exception handling logic.  It is set if all
       calls (if any) are sibling calls.  Such functions do not have to
       have EH tables generated, as they cannot throw.  A call to such a
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.450
diff -c -5 -p -r1.450 tree.h
*** tree.h	26 Oct 2003 08:31:09 -0000	1.450
--- tree.h	5 Nov 2003 09:54:04 -0000
*************** struct tree_common GTY(())
*** 208,217 ****
--- 208,219 ----
     protected_flag:
  
         TREE_PROTECTED in
             BLOCK
  	   ..._DECL
+        CALL_FROM_THUNK_P in
+            CALL_EXPR 
  
     side_effects_flag:
  
         TREE_SIDE_EFFECTS in
             all expressions
*************** struct tree_common GTY(())
*** 260,269 ****
--- 262,272 ----
  
     deprecated_flag:
  
  	TREE_DEPRECATED in
  	   ..._DECL
+ 
  */
  
  /* Define accessors for the fields that all tree nodes have
     (though some fields are not used for all kinds of nodes).  */
  
*************** extern void tree_operand_check_failed (i
*** 618,627 ****
--- 621,634 ----
  #define TREE_NOTHROW(NODE) ((NODE)->common.nothrow_flag)
  
  /* In a CALL_EXPR, means that the address of the return slot is part of the
     argument list.  */
  #define CALL_EXPR_HAS_RETURN_SLOT_ADDR(NODE) ((NODE)->common.private_flag)
+ 
+ /* In a CALL_EXPR, means that the call is the jump from a thunk to the
+    thunked-to function.  */
+ #define CALL_FROM_THUNK_P(NODE) ((NODE)->common.protected_flag)
  
  /* In a type, nonzero means that all objects of the type are guaranteed by the
     language or front-end to be properly aligned, so we can indicate that a MEM
     of this type is aligned at least to the alignment of the type, even if it
     doesn't appear that it is.  We see this, for example, in object-oriented
Index: config/alpha/alpha.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha.c,v
retrieving revision 1.335
diff -c -5 -p -r1.335 alpha.c
*** config/alpha/alpha.c	22 Oct 2003 12:12:15 -0000	1.335
--- config/alpha/alpha.c	5 Nov 2003 09:54:05 -0000
*************** alpha_sa_mask (unsigned long *imaskP, un
*** 6710,6726 ****
  {
    unsigned long imask = 0;
    unsigned long fmask = 0;
    unsigned int i;
  
!   /* Irritatingly, there are two kinds of thunks -- those created with
!      TARGET_ASM_OUTPUT_MI_THUNK and those with DECL_THUNK_P that go
!      through the regular part of the compiler.  In the
!      TARGET_ASM_OUTPUT_MI_THUNK case we don't have valid register life
!      info, but assemble_start_function wants to output .frame and
!      .mask directives.  */
!   if (current_function_is_thunk && !no_new_pseudos)
      {
        *imaskP = 0;
        *fmaskP = 0;
        return;
      }
--- 6710,6723 ----
  {
    unsigned long imask = 0;
    unsigned long fmask = 0;
    unsigned int i;
  
!   /* When outputting a thunk, we don't have valid register life info,
!      but assemble_start_function wants to output .frame and .mask
!      directives.  */
!   if (current_function_is_thunk)
      {
        *imaskP = 0;
        *fmaskP = 0;
        return;
      }
Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.536
diff -c -5 -p -r1.536 rs6000.c
*** config/rs6000/rs6000.c	23 Oct 2003 14:36:23 -0000	1.536
--- config/rs6000/rs6000.c	5 Nov 2003 09:54:09 -0000
*************** rs6000_ra_ever_killed (void)
*** 10734,10748 ****
  {
    rtx top;
    rtx reg;
    rtx insn;
  
!   /* Irritatingly, there are two kinds of thunks -- those created with
!      TARGET_ASM_OUTPUT_MI_THUNK and those with DECL_THUNK_P that go
!      through the regular part of the compiler.  This is a very hacky
!      way to tell them apart.  */
!   if (current_function_is_thunk && !no_new_pseudos)
      return 0;
  
    /* regs_ever_live has LR marked as used if any sibcalls are present,
       but this should not force saving and restoring in the
       pro/epilogue.  Likewise, reg_set_between_p thinks a sibcall
--- 10734,10744 ----
  {
    rtx top;
    rtx reg;
    rtx insn;
  
!   if (current_function_is_thunk)
      return 0;
  
    /* regs_ever_live has LR marked as used if any sibcalls are present,
       but this should not force saving and restoring in the
       pro/epilogue.  Likewise, reg_set_between_p thinks a sibcall
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1150
diff -c -5 -p -r1.1150 decl.c
*** cp/decl.c	24 Oct 2003 07:59:40 -0000	1.1150
--- cp/decl.c	5 Nov 2003 09:54:10 -0000
*************** cxx_push_function_context (struct functi
*** 11126,11137 ****
  
    if (f->decl)
      {
        tree fn = f->decl;
  
-       current_function_is_thunk = DECL_THUNK_P (fn);
- 
        if (DECL_SAVED_FUNCTION_DATA (fn))
  	{
  	  /* If we already parsed this function, and we're just expanding it
  	     now, restore saved state.  */
  	  *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (fn);
--- 11126,11135 ----
Index: cp/method.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/method.c,v
retrieving revision 1.270
diff -c -5 -p -r1.270 method.c
*** cp/method.c	24 Oct 2003 07:59:40 -0000	1.270
--- cp/method.c	5 Nov 2003 09:54:10 -0000
*************** use_thunk (tree thunk_fndecl, bool emit_
*** 478,487 ****
--- 478,488 ----
        t = tree_cons (NULL_TREE, t, NULL_TREE);
        for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
  	t = tree_cons (NULL_TREE, a, t);
        t = nreverse (t);
        t = build_call (alias, t);
+       CALL_FROM_THUNK_P (t) = 1;
        if (!this_adjusting)
  	t = thunk_adjust (t, /*this_adjusting=*/0,
  			  fixed_offset, virtual_offset);
        
        if (VOID_TYPE_P (TREE_TYPE (t)))



More information about the Gcc-patches mailing list