Commit 75d3a15b by Nick Clifton Committed by Nick Clifton

Add thumb-pe support.

Add super interworking.

From-SVN: r18935
parent 7c76b292
Wed Apr 1 17:06:19 1998 Nick Clifton <nickc@cygnus.com>
* config/arm/thumb.h: Add super interworking support.
* config/arm/thumb.c: Add super interworking support.
* config/arm/thumb.md: Add super interworking support.
* config/arm/tpe.h: New file.
* config/arm/lib1funcs.asm: Add interworking support.
* config/arm/lib1thumb.asm: Add super interworking support.
* config/arm/t-pe: New file.
* config/arm/t-semi: Add interworking support.
* config/arm/t-thumb: Add interworking support.
* config/arm/t-pe-thumb: New file.
* config/arm/README-interworking: New file.
* config.sub: Add thumb-pe target.
* configure.in: Add thumb-pe target.
* configure: Add thumb-pe target.
Wed Apr 1 14:38:10 1998 Jim Wilson <wilson@cygnus.com> Wed Apr 1 14:38:10 1998 Jim Wilson <wilson@cygnus.com>
* config/mips/iris6.h (MD_EXEC_PREFIX): Set to /usr/bin/. * config/mips/iris6.h (MD_EXEC_PREFIX): Set to /usr/bin/.
......
...@@ -162,6 +162,10 @@ case $basic_machine in ...@@ -162,6 +162,10 @@ case $basic_machine in
thumb | thumbel) thumb | thumbel)
basic_machine=$basic_machine-unknown basic_machine=$basic_machine-unknown
;; ;;
thumb-pe) # CYGNUS LOCAL nickc/thumb-pe
basic_machine=$basic_machine-unknown
;;
# END CYGNUS LOCAL nickc/thumb-pe
# We use `pc' rather than `unknown' # We use `pc' rather than `unknown'
# because (1) that's what they normally are, and # because (1) that's what they normally are, and
# (2) the word "unknown" tends to confuse beginning users. # (2) the word "unknown" tends to confuse beginning users.
......
...@@ -402,3 +402,120 @@ SYM (__div0): ...@@ -402,3 +402,120 @@ SYM (__div0):
RET pc, lr RET pc, lr
#endif /* L_divmodsi_tools */ #endif /* L_divmodsi_tools */
#ifdef L_dvmd_lnx
@ GNU/Linux division-by zero handler. Used in place of L_dvmd_tls
#include <asm/unistd.h>
#define SIGFPE 8 @ cant use <asm/signal.h> as it
@ contains too much C rubbish
.globl SYM (__div0)
.align 0
SYM (__div0):
stmfd sp!, {r1, lr}
swi __NR_getpid
cmn r0, #1000
ldmgefd sp!, {r1, pc}RETCOND @ not much we can do
mov r1, #SIGFPE
swi __NR_kill
ldmfd sp!, {r1, pc}RETCOND
#endif /* L_dvmd_lnx */
/* These next two sections are here despite the fact that they contain Thumb
assembler because their presence allows interworked code to be linked even
when the GCC library is this one. */
#ifdef L_call_via_rX
/* These labels & instructions are used by the Arm/Thumb interworking code.
The address of function to be called is loaded into a register and then
one of these labels is called via a BL instruction. This puts the
return address into the link register with the bottom bit set, and the
code here switches to the correct mode before executing the function. */
.text
.align 0
.code 16
.macro call_via register
.globl SYM (_call_via_\register)
.thumb_func
SYM (_call_via_\register):
bx \register
nop
.endm
call_via r0
call_via r1
call_via r2
call_via r3
call_via r4
call_via r5
call_via r6
call_via r7
call_via r8
call_via r9
call_via sl
call_via fp
call_via ip
call_via sp
call_via lr
#endif /* L_call_via_rX */
#ifdef L_interwork_call_via_rX
/* These labels & instructions are used by the Arm/Thumb interworking code,
when the target address is in an unknown instruction set. The address
of function to be called is loaded into a register and then one of these
labels is called via a BL instruction. This puts the return address
into the link register with the bottom bit set, and the code here
switches to the correct mode before executing the function. Unfortunately
the target code cannot be relied upon to return via a BX instruction, so
instead we have to store the resturn address on the stack and allow the
called function to return here instead. Upon return we recover the real
return address and use a BX to get back to Thumb mode. */
.text
.align 0
.code 32
_arm_return:
ldmia r13!, {r12}
bx r12
.code 16
.macro interwork register
.code 16
.globl SYM (_interwork_call_via_\register)
.thumb_func
SYM (_interwork_call_via_\register):
bx pc
nop
.code 32
.globl .Lchange_\register
.Lchange_\register:
tst \register, #1
stmeqdb r13!, {lr}
adreq lr, _arm_return
bx \register
.endm
interwork r0
interwork r1
interwork r2
interwork r3
interwork r4
interwork r5
interwork r6
interwork r7
interwork r8
interwork r9
interwork sl
interwork fp
interwork ip
interwork sp
interwork lr
#endif /* L_interwork_call_via_rX */
...@@ -605,98 +605,91 @@ SYM (__div0): ...@@ -605,98 +605,91 @@ SYM (__div0):
one of these labels is called via a BL instruction. This puts the one of these labels is called via a BL instruction. This puts the
return address into the link register with the bottom bit set, and the return address into the link register with the bottom bit set, and the
code here switches to the correct mode before executing the function. */ code here switches to the correct mode before executing the function. */
.text .text
.align 0 .align 0
.globl SYM (_call_via_r0)
.thumb_func
SYM (_call_via_r0):
bx r0
nop
.globl SYM (_call_via_r1)
.thumb_func
SYM (_call_via_r1):
bx r1
nop
.globl SYM (_call_via_r2)
.thumb_func
SYM (_call_via_r2):
bx r2
nop
.globl SYM (_call_via_r3)
.thumb_func
SYM (_call_via_r3):
bx r3
nop
.globl SYM (_call_via_r4)
.thumb_func
SYM (_call_via_r4):
bx r4
nop
.globl SYM (_call_via_r5)
.thumb_func
SYM (_call_via_r5):
bx r5
nop
.globl SYM (_call_via_r6)
.thumb_func
SYM (_call_via_r6):
bx r6
nop
.globl SYM (_call_via_r7) .macro call_via register
.globl SYM (_call_via_\register)
.thumb_func .thumb_func
SYM (_call_via_r7): SYM (_call_via_\register):
bx r7 bx \register
nop nop
.endm
call_via r0
call_via r1
call_via r2
call_via r3
call_via r4
call_via r5
call_via r6
call_via r7
call_via r8
call_via r9
call_via sl
call_via fp
call_via ip
call_via sp
call_via lr
.globl SYM (_call_via_r8) #endif /* L_call_via_rX */
.thumb_func
SYM (_call_via_r8):
bx r8
nop
.globl SYM (_call_via_r9)
.thumb_func
SYM (_call_via_r9):
bx r9
nop
.globl SYM (_call_via_sl)
.thumb_func
SYM (_call_via_sl):
bx sl
nop
.globl SYM (_call_via_fp)
.thumb_func
SYM (_call_via_fp):
bx fp
nop
.globl SYM (_call_via_ip) #ifdef L_interwork_call_via_rX
.thumb_func
SYM (_call_via_ip): /* These labels & instructions are used by the Arm/Thumb interworking code,
bx ip when the target address is in an unknown instruction set. The address
nop of function to be called is loaded into a register and then one of these
labels is called via a BL instruction. This puts the return address
into the link register with the bottom bit set, and the code here
switches to the correct mode before executing the function. Unfortunately
the target code cannot be relied upon to return via a BX instruction, so
instead we have to store the resturn address on the stack and allow the
called function to return here instead. Upon return we recover the real
return address and use a BX to get back to Thumb mode. */
.text
.align 0
.globl SYM (_call_via_sp) .code 32
.thumb_func _arm_return:
SYM (_call_via_sp): ldmia r13!, {r12}
bx sp bx r12
nop .code 16
.globl SYM (_call_via_lr) .macro interwork register
.globl SYM (_interwork_call_via_\register)
.thumb_func .thumb_func
SYM (_call_via_lr): SYM (_interwork_call_via_\register):
bx lr bx pc
nop nop
.code 32
.globl .Lchange_\register
.Lchange_\register:
tst \register, #1
stmeqdb r13!, {lr}
adreq lr, _arm_return
bx \register
.code 16
.endm
interwork r0
interwork r1
interwork r2
interwork r3
interwork r4
interwork r5
interwork r6
interwork r7
interwork r8
interwork r9
interwork sl
interwork fp
interwork ip
interwork sp
interwork lr
#endif /* L_interwork_call_via_rX */
#endif /* L_call_via_rX */
CROSS_LIBGCC1 = libgcc1-asm.a
LIB1ASMSRC = arm/lib1funcs.asm
LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX
# These are really part of libgcc1, but this will cause them to be
# built correctly, so...
LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c
fp-bit.c: $(srcdir)/config/fp-bit.c
echo '#define FLOAT' > fp-bit.c
echo '#ifndef __ARMEB__' >> fp-bit.c
echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c
echo '#endif' >> fp-bit.c
cat $(srcdir)/config/fp-bit.c >> fp-bit.c
dp-bit.c: $(srcdir)/config/fp-bit.c
echo '#ifndef __ARMEB__' > dp-bit.c
echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c
echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c
echo '#endif' >> dp-bit.c
cat $(srcdir)/config/fp-bit.c >> dp-bit.c
pe.o: $(srcdir)/config/arm/pe.c
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/arm/pe.c
MULTILIB_OPTIONS = mhard-float
MULTILIB_DIRNAMES = fpu
LIBGCC = stmp-multilib
INSTALL_LIBGCC = install-multilib
# Makefile fragment
# Copyright (c) 1998 Free Software Foundation
# CYGNUS LOCAL (entire file) nickc/thumb-pe
CROSS_LIBGCC1 = libgcc1-asm.a
LIB1ASMSRC = arm/lib1thumb.asm
LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX
# These are really part of libgcc1, but this will cause them to be
# built correctly, so...
LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c
fp-bit.c: $(srcdir)/config/fp-bit.c
echo '#define FLOAT' > fp-bit.c
echo '#ifndef __ARMEB__' >> fp-bit.c
echo '#define FLOAT_BIT_ORDER_MISMATCH' >> fp-bit.c
echo '#endif' >> fp-bit.c
cat $(srcdir)/config/fp-bit.c >> fp-bit.c
dp-bit.c: $(srcdir)/config/fp-bit.c
echo '#ifndef __ARMEB__' > dp-bit.c
echo '#define FLOAT_BIT_ORDER_MISMATCH' >> dp-bit.c
echo '#define FLOAT_WORD_ORDER_MISMATCH' >> dp-bit.c
echo '#endif' >> dp-bit.c
cat $(srcdir)/config/fp-bit.c >> dp-bit.c
# Rule to build Psion specific GCC functions.
pe.o: $(srcdir)/config/arm/pe.c
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/arm/pe.c
# Avoid building a duplicate set of libraries for the default endian-ness.
MULTILIB_OPTIONS = mthumb-interwork
MULTILIB_DIRNAMES = interwork
LIBGCC = stmp-multilib
INSTALL_LIBGCC = install-multilib
...@@ -11,7 +11,7 @@ LIBGCC1_TEST = ...@@ -11,7 +11,7 @@ LIBGCC1_TEST =
CROSS_LIBGCC1 = libgcc1-asm.a CROSS_LIBGCC1 = libgcc1-asm.a
LIB1ASMSRC = arm/lib1funcs.asm LIB1ASMSRC = arm/lib1funcs.asm
LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX
#Don't try to run fixproto #Don't try to run fixproto
STMP_FIXPROTO = STMP_FIXPROTO =
......
CROSS_LIBGCC1 = libgcc1-asm.a CROSS_LIBGCC1 = libgcc1-asm.a
LIB1ASMSRC = arm/lib1thumb.asm LIB1ASMSRC = arm/lib1thumb.asm
LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls _call_via_rX _interwork_call_via_rX
# adddi3/subdi3 added to machine description # adddi3/subdi3 added to machine description
#LIB1ASMFUNCS = _adddi3 _subdi3 _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls #LIB1ASMFUNCS = _adddi3 _subdi3 _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_tls
......
...@@ -540,6 +540,43 @@ thumb_reload_out_si (operands) ...@@ -540,6 +540,43 @@ thumb_reload_out_si (operands)
abort (); abort ();
} }
#ifdef THUMB_PE /* CYGNUS LOCAL nickc/thumb-pe */
/* Return non-zero if FUNC is a naked function. */
static int
arm_naked_function_p (func)
tree func;
{
tree a;
if (TREE_CODE (func) != FUNCTION_DECL)
abort ();
a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func));
return a != NULL_TREE;
}
#endif /* END CYGNUS LOCAL nickc/thumb-pe */
/* CYGNUS LOCAL nickc/super-interworking */
/* Return non-zero if FUNC must be entered in ARM mode. */
int
is_called_in_ARM_mode (func)
tree func;
{
if (TREE_CODE (func) != FUNCTION_DECL)
abort ();
/* Ignore the problem about functions whoes address is taken. */
if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func))
return TRUE;
#ifdef THUMB_PE
return lookup_attribute ("interfacearm", DECL_MACHINE_ATTRIBUTES (func)) != NULL_TREE;
#else
return FALSE;
#endif
}
/* END CYGNUS LOCAL */
/* Routines for emitting code */ /* Routines for emitting code */
...@@ -585,10 +622,9 @@ number_of_first_bit_set (mask) ...@@ -585,10 +622,9 @@ number_of_first_bit_set (mask)
#define LINK_REGISTER 14 #define LINK_REGISTER 14
#define PROGRAM_COUNTER 15 #define PROGRAM_COUNTER 15
/* Generate code to return from a thumb function. /* Generate code to return from a thumb function. If
If 'reg_containing_return_addr' is -1, then the 'reg_containing_return_addr' is -1, then the return address is
address is actually on the stack, at the stack actually on the stack, at the stack pointer. */
pointer. */
static void static void
thumb_exit (f, reg_containing_return_addr) thumb_exit (f, reg_containing_return_addr)
...@@ -634,9 +670,15 @@ thumb_exit (f, reg_containing_return_addr) ...@@ -634,9 +670,15 @@ thumb_exit (f, reg_containing_return_addr)
} }
/* Otherwise if we are not supporting interworking and we have not created /* Otherwise if we are not supporting interworking and we have not created
a backtrace structure then just pop the return address straight into the PC. */ a backtrace structure and the function was not entered in ARM mode then
just pop the return address straight into the PC. */
else if (! TARGET_THUMB_INTERWORK && ! TARGET_BACKTRACE) else if ( ! TARGET_THUMB_INTERWORK
&& ! TARGET_BACKTRACE
/* CYGNUS LOCAL nickc/super-interworking */
&& ! is_called_in_ARM_mode (current_function_decl)
/* END CYGNUS LOCAL */
)
{ {
asm_fprintf (f, "\tpop\t{pc}\n" ); asm_fprintf (f, "\tpop\t{pc}\n" );
...@@ -926,7 +968,7 @@ thumb_pushpop (f, mask, push) ...@@ -926,7 +968,7 @@ thumb_pushpop (f, mask, push)
if (mask & 0xFF) if (mask & 0xFF)
asm_fprintf (f, ", "); asm_fprintf (f, ", ");
asm_fprintf (f, "%s", reg_names[14]); asm_fprintf (f, reg_names[14]);
} }
else if (!push && (mask & (1 << 15))) else if (!push && (mask & (1 << 15)))
{ {
...@@ -948,7 +990,7 @@ thumb_pushpop (f, mask, push) ...@@ -948,7 +990,7 @@ thumb_pushpop (f, mask, push)
if (mask & 0xFF) if (mask & 0xFF)
asm_fprintf (f, ", "); asm_fprintf (f, ", ");
asm_fprintf (f, "%s", reg_names[15]); asm_fprintf (f, reg_names[15]);
} }
} }
...@@ -995,7 +1037,12 @@ output_return () ...@@ -995,7 +1037,12 @@ output_return ()
{ {
thumb_exit (asm_out_file, 14); thumb_exit (asm_out_file, 14);
} }
else if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) else if ( TARGET_THUMB_INTERWORK
|| TARGET_BACKTRACE
/* CYGNUS LOCAL nickc/super-interworking */
|| is_called_in_ARM_mode (current_function_decl)
/* END CYGNUS LOCAL */
)
{ {
thumb_exit (asm_out_file, -1); thumb_exit (asm_out_file, -1);
} }
...@@ -1014,7 +1061,12 @@ output_return () ...@@ -1014,7 +1061,12 @@ output_return ()
asm_fprintf (asm_out_file, ", "); asm_fprintf (asm_out_file, ", ");
} }
if (TARGET_THUMB_INTERWORK || TARGET_BACKTRACE) if ( TARGET_THUMB_INTERWORK
|| TARGET_BACKTRACE
/* CYGNUS LOCAL nickc/super-interworking */
|| is_called_in_ARM_mode (current_function_decl)
/* END CYGNUS LOCAL */
)
{ {
asm_fprintf (asm_out_file, "}\n"); asm_fprintf (asm_out_file, "}\n");
thumb_exit (asm_out_file, -1); thumb_exit (asm_out_file, -1);
...@@ -1037,6 +1089,43 @@ thumb_function_prologue (f, frame_size) ...@@ -1037,6 +1089,43 @@ thumb_function_prologue (f, frame_size)
int store_arg_regs = 0; int store_arg_regs = 0;
int regno; int regno;
#ifdef THUMB_PE /* CYGNUS LOCAL nickc/thumb-pe */
if (arm_naked_function_p (current_function_decl))
return;
#endif /* CYGNUS LOCAL nickc/thumb-pe */
/* CYGNUS LOCAL nickc/super-interworking */
if (is_called_in_ARM_mode (current_function_decl))
{
char * name;
if (GET_CODE (DECL_RTL (current_function_decl)) != MEM)
abort();
if (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0)) != SYMBOL_REF)
abort();
name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
/* Generate code sequence to switch us into Thumb mode. */
/* The .code 32 directive has already been emitted by
ASM_DECLARE_FUNCITON_NAME */
asm_fprintf (f, "\torr\tr12, pc, #1\n");
asm_fprintf (f, "\tbx\tr12\n");
/* Generate a label, so that the debugger will notice the
change in instruction sets. This label is also used by
the assembler to bypass the ARM code when this function
is called from a Thumb encoded function elsewhere in the
same file. Hence the definition of STUB_NAME here must
agree with the definition in gas/config/tc-arm.c */
#define STUB_NAME ".real_start_of"
asm_fprintf (f, "\t.code\t16\n");
asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name);
asm_fprintf (f, "\t.thumb_func\n");
asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
}
/* END CYGNUS LOCAL nickc/super-interworking */
if (current_function_anonymous_args && current_function_pretend_args_size) if (current_function_anonymous_args && current_function_pretend_args_size)
store_arg_regs = 1; store_arg_regs = 1;
...@@ -1318,7 +1407,7 @@ thumb_unexpanded_epilogue () ...@@ -1318,7 +1407,7 @@ thumb_unexpanded_epilogue ()
int high_regs_pushed = 0; int high_regs_pushed = 0;
int leaf_function = leaf_function_p (); int leaf_function = leaf_function_p ();
int had_to_push_lr; int had_to_push_lr;
if (return_used_this_function) if (return_used_this_function)
return ""; return "";
...@@ -1329,7 +1418,7 @@ thumb_unexpanded_epilogue () ...@@ -1329,7 +1418,7 @@ thumb_unexpanded_epilogue ()
for (regno = 8; regno < 13; regno++) for (regno = 8; regno < 13; regno++)
{ {
if (regs_ever_live[regno] && ! call_used_regs[regno]) if (regs_ever_live[regno] && ! call_used_regs[regno])
high_regs_pushed++; high_regs_pushed ++;
} }
/* The prolog may have pushed some high registers to use as /* The prolog may have pushed some high registers to use as
...@@ -1385,7 +1474,6 @@ thumb_unexpanded_epilogue () ...@@ -1385,7 +1474,6 @@ thumb_unexpanded_epilogue ()
while (high_regs_pushed) while (high_regs_pushed)
{ {
/* Find low register(s) into which the high register(s) can be popped. */ /* Find low register(s) into which the high register(s) can be popped. */
for (regno = 0; regno < 8; regno++) for (regno = 0; regno < 8; regno++)
{ {
if (mask & (1 << regno)) if (mask & (1 << regno))
...@@ -1397,11 +1485,9 @@ thumb_unexpanded_epilogue () ...@@ -1397,11 +1485,9 @@ thumb_unexpanded_epilogue ()
mask &= (2 << regno) - 1; /* A noop if regno == 8 */ mask &= (2 << regno) - 1; /* A noop if regno == 8 */
/* Pop the values into the low register(s). */ /* Pop the values into the low register(s). */
thumb_pushpop (asm_out_file, mask, 0); thumb_pushpop (asm_out_file, mask, 0);
/* Move the value(s) into the high registers. */ /* Move the value(s) into the high registers. */
for (regno = 0; regno < 8; regno++) for (regno = 0; regno < 8; regno++)
{ {
if (mask & (1 << regno)) if (mask & (1 << regno))
...@@ -1419,11 +1505,6 @@ thumb_unexpanded_epilogue () ...@@ -1419,11 +1505,6 @@ thumb_unexpanded_epilogue ()
had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p()); had_to_push_lr = (live_regs_mask || ! leaf_function || far_jump_used_p());
if (had_to_push_lr)
{
live_regs_mask |= 1 << PROGRAM_COUNTER;
}
if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0) if (TARGET_BACKTRACE && ((live_regs_mask & 0xFF) == 0) && regs_ever_live[ ARG_4_REGISTER ] != 0)
{ {
/* The stack backtrace structure creation code had to /* The stack backtrace structure creation code had to
...@@ -1435,6 +1516,13 @@ thumb_unexpanded_epilogue () ...@@ -1435,6 +1516,13 @@ thumb_unexpanded_epilogue ()
if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE) if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE)
{ {
if (had_to_push_lr
/* CYGNUS LOCAL nickc/super-interworking */
&& ! is_called_in_ARM_mode (current_function_decl)
/* END CYGNUS LOCAL nickc/super-interworking */
)
live_regs_mask |= 1 << PROGRAM_COUNTER;
/* Either no argument registers were pushed or a backtrace /* Either no argument registers were pushed or a backtrace
structure was created which includes an adjusted stack structure was created which includes an adjusted stack
pointer, so just pop everything. */ pointer, so just pop everything. */
...@@ -1443,15 +1531,23 @@ thumb_unexpanded_epilogue () ...@@ -1443,15 +1531,23 @@ thumb_unexpanded_epilogue ()
thumb_pushpop (asm_out_file, live_regs_mask, FALSE); thumb_pushpop (asm_out_file, live_regs_mask, FALSE);
/* We have either just popped the return address into the /* We have either just popped the return address into the
PC or it is was kept in LR for the entire function. */ PC or it is was kept in LR for the entire function or
it is still on the stack because we do not want to
return by doing a pop {pc}. */
if (! had_to_push_lr) if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0)
thumb_exit (asm_out_file, LINK_REGISTER); thumb_exit (asm_out_file,
(
had_to_push_lr
/* CYGNUS LOCAL nickc/super-interworking */
&& is_called_in_ARM_mode (current_function_decl)
/* END CYGNUS LOCAL */
) ? -1 : LINK_REGISTER
);
} }
else else
{ {
/* Pop everything but the return address. */ /* Pop everything but the return address. */
live_regs_mask &= ~ (1 << PROGRAM_COUNTER); live_regs_mask &= ~ (1 << PROGRAM_COUNTER);
if (live_regs_mask) if (live_regs_mask)
...@@ -1460,15 +1556,13 @@ thumb_unexpanded_epilogue () ...@@ -1460,15 +1556,13 @@ thumb_unexpanded_epilogue ()
if (had_to_push_lr) if (had_to_push_lr)
{ {
/* Get the return address into a temporary register. */ /* Get the return address into a temporary register. */
thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0); thumb_pushpop (asm_out_file, 1 << ARG_4_REGISTER, 0);
} }
/* Remove the argument registers that were pushed onto the stack. */ /* Remove the argument registers that were pushed onto the stack. */
asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n", asm_fprintf (asm_out_file, "\tadd\t%s, %s, #%d\n",
reg_names[STACK_POINTER], reg_names [STACK_POINTER],
reg_names[STACK_POINTER], reg_names [STACK_POINTER],
current_function_pretend_args_size); current_function_pretend_args_size);
thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER); thumb_exit (asm_out_file, had_to_push_lr ? ARG_4_REGISTER : LINK_REGISTER);
...@@ -1963,3 +2057,36 @@ void thumb_override_options() ...@@ -1963,3 +2057,36 @@ void thumb_override_options()
warning ("Structure size boundary can only be set to 8 or 32"); warning ("Structure size boundary can only be set to 8 or 32");
} }
} }
#ifdef THUMB_PE /* CYGNUS LOCAL nickc/thumb-pe */
/* Return nonzero if ATTR is a valid attribute for DECL.
ATTRIBUTES are any existing attributes and ARGS are the arguments
supplied with ATTR.
Supported attributes:
naked: don't output any prologue or epilogue code, the user is assumed
to do the right thing.
interfacearm: Always assume that this function will be entered in ARM
mode, not Thumb mode, and that the caller wishes to be returned to in
ARM mode. */
int
arm_valid_machine_decl_attribute (decl, attributes, attr, args)
tree decl;
tree attributes;
tree attr;
tree args;
{
if (args != NULL_TREE)
return 0;
if (is_attribute_p ("naked", attr))
return TREE_CODE (decl) == FUNCTION_DECL;
if (is_attribute_p ("interfacearm", attr))
return TREE_CODE (decl) == FUNCTION_DECL;
return 0;
}
#endif /* END CYGNUS LOCAL nickc/thumb-pe */
...@@ -55,36 +55,63 @@ Boston, MA 02111-1307, USA. */ ...@@ -55,36 +55,63 @@ Boston, MA 02111-1307, USA. */
#define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr); #define TARGET_VERSION fputs (" (ARM/THUMB:generic)", stderr);
/* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */ /* Nonzero if we should compile with BYTES_BIG_ENDIAN set to 1. */
#define THUMB_FLAG_BIG_END (0x0001) #define THUMB_FLAG_BIG_END 0x0001
#define THUMB_FLAG_BACKTRACE (0x0002) #define THUMB_FLAG_BACKTRACE 0x0002
#define THUMB_FLAG_LEAF_BACKTRACE (0x0004) #define THUMB_FLAG_LEAF_BACKTRACE 0x0004
#define ARM_FLAG_THUMB (0x1000) /* same as in arm.h */ #define ARM_FLAG_THUMB 0x1000 /* same as in arm.h */
#define THUMB_FLAG_CALLEE_SUPER_INTERWORKING 0x40000 /* CYGNUS LOCAL nickc */
#define THUMB_FLAG_CALLER_SUPER_INTERWORKING 0x80000 /* CYGNUS LOCAL nickc */
/* Run-time compilation parameters selecting different hardware/software subsets. */ /* Run-time compilation parameters selecting different hardware/software subsets. */
extern int target_flags; extern int target_flags;
#define TARGET_DEFAULT 0 /* ARM_FLAG_THUMB */ #define TARGET_DEFAULT 0 /* ARM_FLAG_THUMB */
#define TARGET_BIG_END (target_flags & THUMB_FLAG_BIG_END) #define TARGET_BIG_END (target_flags & THUMB_FLAG_BIG_END)
#define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB) #define TARGET_THUMB_INTERWORK (target_flags & ARM_FLAG_THUMB)
#define TARGET_BACKTRACE (leaf_function_p() \ #define TARGET_BACKTRACE (leaf_function_p() \
? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \ ? (target_flags & THUMB_FLAG_LEAF_BACKTRACE) \
: (target_flags & THUMB_FLAG_BACKTRACE)) : (target_flags & THUMB_FLAG_BACKTRACE))
#define TARGET_SWITCHES \ /* CYGNUS LOCAL nickc/super-interworking */
{ \ /* Set if externally visable functions should assume that they
{"big-endian", THUMB_FLAG_BIG_END}, \ might be called in ARM mode, from a non-thumb aware code. */
{"little-endian", -THUMB_FLAG_BIG_END}, \ #define TARGET_CALLEE_INTERWORKING \
{"thumb-interwork", ARM_FLAG_THUMB}, \ (target_flags & THUMB_FLAG_CALLEE_SUPER_INTERWORKING)
{"no-thumb-interwork", -ARM_FLAG_THUMB}, \
{"tpcs-frame", THUMB_FLAG_BACKTRACE}, \ /* Set if calls via function pointers should assume that their
{"no-tpcs-frame", -THUMB_FLAG_BACKTRACE}, \ destination is non-Thumb aware. */
{"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE}, \ #define TARGET_CALLER_INTERWORKING \
{"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE}, \ (target_flags & THUMB_FLAG_CALLER_SUPER_INTERWORKING)
{"", TARGET_DEFAULT} \ /* END CYGNUS LOCAL */
/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. */
#ifndef SUBTARGET_SWITCHES
#define SUBTARGET_SWITCHES
#endif
#define TARGET_SWITCHES \
{ \
{"big-endian", THUMB_FLAG_BIG_END}, \
{"little-endian", -THUMB_FLAG_BIG_END}, \
{"thumb-interwork", ARM_FLAG_THUMB}, \
{"no-thumb-interwork", -ARM_FLAG_THUMB}, \
{"tpcs-frame", THUMB_FLAG_BACKTRACE}, \
{"no-tpcs-frame", -THUMB_FLAG_BACKTRACE}, \
{"tpcs-leaf-frame", THUMB_FLAG_LEAF_BACKTRACE}, \
{"no-tpcs-leaf-frame", -THUMB_FLAG_LEAF_BACKTRACE}, \
/* CYGNUS LOCAL nickc/super-interworking */ \
{"callee-super-interworking", THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \
{"no-callee-super-interworking", -THUMB_FLAG_CALLEE_SUPER_INTERWORKING}, \
{"caller-super-interworking", THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \
{"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING}, \
/* END CYGNUS LOCAL */ \
SUBTARGET_SWITCHES \
{"", TARGET_DEFAULT} \
} }
#define TARGET_OPTIONS \ #define TARGET_OPTIONS \
{ \ { \
{ "structure-size-boundary=", & structure_size_string }, \ { "structure-size-boundary=", & structure_size_string }, \
} }
#define REGISTER_PREFIX "" #define REGISTER_PREFIX ""
...@@ -1026,7 +1053,12 @@ int thumb_shiftable_const (); ...@@ -1026,7 +1053,12 @@ int thumb_shiftable_const ();
/* Emit a special directive when defining a function name. /* Emit a special directive when defining a function name.
This is used by the assembler to assit with interworking. */ This is used by the assembler to assit with interworking. */
#define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \ #define ASM_DECLARE_FUNCTION_NAME(file, name, decl) \
fprintf (file, ".thumb_func\n") ; \ /* CYGNUS LOCAL nickc/supr-interworking */ \
if (! is_called_in_ARM_mode (decl)) \
fprintf (file, "\t.thumb_func\n") ; \
else \
fprintf (file, "\t.code\t32\n") ; \
/* END CYGNUS LOCAL */ \
ASM_OUTPUT_LABEL (file, name) ASM_OUTPUT_LABEL (file, name)
#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ #define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \
...@@ -1095,8 +1127,10 @@ int thumb_shiftable_const (); ...@@ -1095,8 +1127,10 @@ int thumb_shiftable_const ();
int thumb_trivial_epilogue (); int thumb_trivial_epilogue ();
#define USE_RETURN (reload_completed && thumb_trivial_epilogue ()) #define USE_RETURN (reload_completed && thumb_trivial_epilogue ())
extern char *thumb_unexpanded_epilogue (); extern char * thumb_unexpanded_epilogue ();
extern char *output_move_mem_multiple (); extern char * output_move_mem_multiple ();
extern char *thumb_load_double_from_address (); extern char * thumb_load_double_from_address ();
extern char *output_return (); extern char * output_return ();
extern int far_jump_used_p(); extern int far_jump_used_p();
extern int is_called_in_ARM_mode (); /* CYGNUS LOCAL */
...@@ -989,19 +989,20 @@ ...@@ -989,19 +989,20 @@
(define_insn "*call_indirect" (define_insn "*call_indirect"
[(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
(match_operand 1 "" ""))] (match_operand 1 "" ""))]
"TARGET_THUMB_INTERWORK" "! TARGET_CALLER_INTERWORKING"
"bl\\t__call_via_%0" "bl\\t__call_via_%0"
[(set_attr "length" "4")]) [(set_attr "length" "4")])
;; The non THUMB_INTERWORK, non TARGET_CALLER_INTERWORKING version
;; used to be: "mov\\tlr,pc\;bx\\t%0", but the mov does not set
;; the bottom bit of lr so that a function return (using bx)
;; would switch back into ARM mode...
(define_insn "*call_indirect_interwork"
(define_insn "*call_indirect"
[(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r"))
(match_operand 1 "" ""))] (match_operand 1 "" ""))]
"! TARGET_THUMB_INTERWORK" "TARGET_CALLER_INTERWORKING"
"bl\\t__call_via_%0" "bl\\t__interwork_call_via_%0"
[(set_attr "length" "4")]) [(set_attr "length" "4")])
;; used to be: "mov\\tlr,pc\;bx\\t%0"
;; but this does not set bottom bit of lr
(define_expand "call_value" (define_expand "call_value"
[(set (match_operand 0 "" "") [(set (match_operand 0 "" "")
...@@ -1014,19 +1015,19 @@ ...@@ -1014,19 +1015,19 @@
[(set (match_operand 0 "" "=l") [(set (match_operand 0 "" "=l")
(call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
(match_operand 2 "" "")))] (match_operand 2 "" "")))]
"TARGET_THUMB_INTERWORK" "! TARGET_CALLER_INTERWORKING"
"bl\\t__call_via_%1" "bl\\t__call_via_%1"
[(set_attr "length" "4")]) [(set_attr "length" "4")])
;; See comment for call_indirect pattern
(define_insn "*call_value_indirect" (define_insn "*call_value_indirect_interwork"
[(set (match_operand 0 "" "=l") [(set (match_operand 0 "" "=l")
(call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) (call (mem:SI (match_operand:SI 1 "register_operand" "l*r"))
(match_operand 2 "" "")))] (match_operand 2 "" "")))]
"! TARGET_THUMB_INTERWORK" "TARGET_CALLER_INTERWORKING"
"bl\\t__call_via_%1" "bl\\t__interwork_call_via_%1"
[(set_attr "length" "4")]) [(set_attr "length" "4")])
;; used to be "mov\\tlr,pc\;bx\\t%1"
;; but this does not set bottom bit of lr
(define_insn "*call_insn" (define_insn "*call_insn"
[(call (mem:SI (match_operand:SI 0 "" "i")) [(call (mem:SI (match_operand:SI 0 "" "i"))
......
...@@ -4175,6 +4175,16 @@ for machine in $build $host $target; do ...@@ -4175,6 +4175,16 @@ for machine in $build $host $target; do
md_file=arm/thumb.md md_file=arm/thumb.md
tmake_file=arm/t-thumb tmake_file=arm/t-thumb
;; ;;
# CYGNUS LOCAL thumb-pe/nickc
thumb-*-pe)
tm_file=arm/tpe.h
out_file=arm/thumb.c
xm_file=arm/xm-thumb.h
md_file=arm/thumb.md
tmake_file=arm/t-pe-thumb
extra_objs=pe.o
;;
# END CYGNUS LOCAL
# This hasn't been upgraded to GCC 2. # This hasn't been upgraded to GCC 2.
# tron-*-*) # tron-*-*)
# cpu_type=gmicro # cpu_type=gmicro
......
...@@ -2492,6 +2492,16 @@ for machine in $build $host $target; do ...@@ -2492,6 +2492,16 @@ for machine in $build $host $target; do
md_file=arm/thumb.md md_file=arm/thumb.md
tmake_file=arm/t-thumb tmake_file=arm/t-thumb
;; ;;
# CYGNUS LOCAL thumb-pe/nickc
thumb-*-pe)
tm_file=arm/tpe.h
out_file=arm/thumb.c
xm_file=arm/xm-thumb.h
md_file=arm/thumb.md
tmake_file=arm/t-pe-thumb
extra_objs=pe.o
;;
# END CYGNUS LOCAL
# This hasn't been upgraded to GCC 2. # This hasn't been upgraded to GCC 2.
# tron-*-*) # tron-*-*)
# cpu_type=gmicro # cpu_type=gmicro
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment