This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Emitting THUNKS for Thumb code
- From: Richard Earnshaw <rearnsha at arm dot com>
- To: gcc at gcc dot gnu dot org, jason at redhat dot com
- Cc: Richard dot Earnshaw at arm dot com
- Date: Wed, 26 Jun 2002 15:28:52 +0100
- Subject: Emitting THUNKS for Thumb code
- Organization: ARM Ltd.
- Reply-to: Richard dot Earnshaw at arm dot com
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. */