This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Emitting THUNKS for Thumb code


I'm trying to solve a problem I've come across with the generation of 
thunks for Thumb code.  The ASM_OUTPUT_MI_THUNK code is currently written 
to work only in ARM mode, but the thumb equivalent would be so long that 
it is more efficient to switch into ARM mode, execute the thunk and then 
branch back again.

However, I'm running into a problem.  In order to do this efficiently I 
need to mark the label at the start of the thunk as being an ARM code 
label.  The following patch achieves this, but has the nasty consequence 
that the arm back-end needs to include cp/cp-tree.h so that I can access 
the language-specific tree fields (since we have two ways of generating 
thunks, one using ASM_OUTPUT_MI_THUNK and one using a normal call-return 
sequence).  This seems to be the wrong approach to me, but I can't think 
of anything else.

Does anyone have a better solution to this?

R.
Index: arm-protos.h
===================================================================
RCS file: /thirdparty/cvs/gnu/gcc/gcc/config/arm/arm-protos.h,v
retrieving revision 1.3
diff -p -r1.3 arm-protos.h
*** arm-protos.h	2001/08/10 14:54:54	1.3
--- arm-protos.h	2002/06/26 14:21:18
*************** extern rtx    arm_function_arg		PARAMS (
*** 142,147 ****
--- 142,148 ----
  						enum machine_mode, tree, int));
  extern void   arm_init_cumulative_args	PARAMS ((CUMULATIVE_ARGS *, tree, rtx,
  						int));
+ extern void   arm_asm_output_mi_thunk	PARAMS ((FILE *, tree, int, tree));
  #endif
  
  #if defined AOF_ASSEMBLER 
Index: arm.c
===================================================================
RCS file: /thirdparty/cvs/gnu/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.9
diff -p -r1.9 arm.c
*** arm.c	2002/06/24 15:38:01	1.9
--- arm.c	2002/06/26 14:21:18
*************** Boston, MA 02111-1307, USA.  */
*** 36,42 ****
  #include "insn-attr.h"
  #include "flags.h"
  #include "reload.h"
- #include "function.h"
  #include "expr.h"
  #include "toplev.h"
  #include "recog.h"
--- 36,41 ----
*************** Boston, MA 02111-1307, USA.  */
*** 44,49 ****
--- 43,49 ----
  #include "except.h"
  #include "c-pragma.h"
  #include "tm_p.h"
+ #include "cp/cp-tree.h"
  
  /* Forward definitions of types.  */
  typedef struct minipool_node    Mnode;
*************** arm_print_operand (stream, x, code)
*** 8605,8610 ****
--- 8605,8668 ----
  	}
      }
  }
+ 
+ /* Output code to add DELTA to the first argument, and then jump to FUNCTION.
+    Used for C++ multiple inheritance.  */
+ /* For ARM code the sequence is simple, and can be done with a simple 
+    adjustment follwoed by a branch.
+    For Thumb code there is no efficient way to do this, since a branch
+    instruction cannot span a sufficient range.  Fortunately, we will
+    always arrive at a thunk from thumb code via a bx instruction, so
+    we can code the thunk in ARM code.  All we have to take care of
+    is the switch back to Thumb mode.  */
+ void
+ arm_asm_output_mi_thunk (file, thunk_fndecl, delta, function)
+      FILE *file;
+      tree thunk_fndecl;
+      int delta;
+      tree function;
+ {
+   int mi_delta = delta;
+   const char * mi_op = mi_delta < 0 ? "sub" : "add";
+   int shift = 0;
+   int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)))
+ 		    ? 1 : 0);
+ 
+   if (mi_delta < 0)
+     mi_delta = - mi_delta;
+ 
+   while (mi_delta != 0)
+     {
+       if ((mi_delta & (3 << shift)) == 0)
+ 	shift += 2;
+       else
+ 	{
+ 	  asm_fprintf (file, "\t%s\t%r, %r, #%d\n",
+ 		       mi_op, this_regno, this_regno,
+ 		       mi_delta & (0xff << shift));
+ 	  mi_delta &= ~(0xff << shift);
+ 	  shift += 8;
+ 	}
+     }
+ 
+   if (TARGET_THUMB && !(flag_pic))
+     {
+       asm_fprintf (file, "\tldr\t%r, [%r]\n", IP_REGNUM, PC_REGNUM);
+       asm_fprintf (file, "\tbx\t%r\n", IP_REGNUM);
+       ASM_OUTPUT_INT (file, XEXP (DECL_RTL (function), 0));
+     }
+   else
+     {
+       fputs ("\tb\t", file);
+       assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
+       if (NEED_PLT_RELOC)
+ 	fputs ("(PLT)", file);
+       fputc ('\n', file);
+     }
+ 
+   if (TARGET_THUMB)
+     fputs ("\t.thumb\n", file);
+ }
  
  /* A finite state machine takes care of noticing whether or not instructions
     can be conditionally executed, and thus decrease execution time and code
*************** is_called_in_ARM_mode (func)
*** 9825,9830 ****
--- 9883,9893 ----
  
    /* Ignore the problem about functions whoes address is taken.  */
    if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func))
+     return TRUE;
+ 
+   /* Thunks that use the MI_THUNK mechanism are also called in ARM mode.  */
+   if (current_function_is_thunk
+       && !THUNK_VCALL_OFFSET (current_function_decl))
      return TRUE;
  
  #ifdef ARM_PE 
Index: arm.h
===================================================================
RCS file: /thirdparty/cvs/gnu/gcc/gcc/config/arm/arm.h,v
retrieving revision 1.9
diff -p -r1.9 arm.h
*** arm.h	2002/03/20 11:38:52	1.9
--- arm.h	2002/06/26 14:21:18
*************** extern int making_const_table;
*** 3040,3075 ****
  
  /* Output code to add DELTA to the first argument, and then jump to FUNCTION.
     Used for C++ multiple inheritance.  */
! #define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION)		\
!   do										\
!     {										\
!       int mi_delta = (DELTA);							\
!       const char * mi_op = mi_delta < 0 ? "sub" : "add";			\
!       int shift = 0;								\
!       int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION)))	\
! 		        ? 1 : 0);						\
!       if (mi_delta < 0)								\
!         mi_delta = - mi_delta;							\
!       while (mi_delta != 0)							\
!         {									\
!           if ((mi_delta & (3 << shift)) == 0)					\
! 	    shift += 2;								\
!           else									\
! 	    {									\
! 	      asm_fprintf (FILE, "\t%s\t%r, %r, #%d\n",				\
! 		           mi_op, this_regno, this_regno,			\
! 		           mi_delta & (0xff << shift));				\
! 	      mi_delta &= ~(0xff << shift);					\
! 	      shift += 8;							\
! 	    }									\
!         }									\
!       fputs ("\tb\t", FILE);							\
!       assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0));		\
!       if (NEED_PLT_RELOC)							\
!         fputs ("(PLT)", FILE);							\
!       fputc ('\n', FILE);							\
!     }										\
!   while (0)
  
  /* A C expression whose value is RTL representing the value of the return
     address for the frame COUNT steps up from the current frame.  */
--- 3040,3047 ----
  
  /* Output code to add DELTA to the first argument, and then jump to FUNCTION.
     Used for C++ multiple inheritance.  */
! #define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION)	\
!   arm_asm_output_mi_thunk ((FILE), (THUNK_FNDECL), (DELTA), (FUNCTION))
  
  /* A C expression whose value is RTL representing the value of the return
     address for the frame COUNT steps up from the current frame.  */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]