aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/arm/arm.c
diff options
context:
space:
mode:
authorRichard Earnshaw <rearnsha@arm.com>2004-06-25 10:42:21 +0000
committerRichard Earnshaw <rearnsha@gcc.gnu.org>2004-06-25 10:42:21 +0000
commit68d560d4d612ad0683bae7b36708ef88685316c5 (patch)
tree7fbbce5dce641445636037d4f40a6ff09f75b128 /gcc/config/arm/arm.c
parent576df3214c16163b65f82064f035fd375d0c02aa (diff)
downloadgcc-68d560d4d612ad0683bae7b36708ef88685316c5.zip
gcc-68d560d4d612ad0683bae7b36708ef88685316c5.tar.gz
gcc-68d560d4d612ad0683bae7b36708ef88685316c5.tar.bz2
arm.c (arm_arch4t): New variable.
* arm.c (arm_arch4t): New variable. (arm_override_options): Initialize it. If compiling for armv5 or higher clear TARGET_INTERWORK. (output_call): Abort if called for armv5. Use BX if it's available. (output_call_mem): Use BLX if available and ensure that all armv5 code is interworking safe. (output_return_instruction): Always use BX in preference to MOV if it's available. (arm_output_epilogue): Likewise. (arm_final_prescan_insn): Never conditionally call a subroutine on armv5. * arm.h (arm_arch4t): Declare. * arm.md (call_reg_armv5, call_value_reg_armv5): New. (call_reg_arm, call_value_reg_arm): Renamed from call_reg and call_value_reg respectively. (call_reg_thumb_v5, call_value_reg_thumb_v5): New. (call_reg_thumb, call_value_reg_thumb): Renamed from call_indirect and call_value_indirect respectively. From-SVN: r83647
Diffstat (limited to 'gcc/config/arm/arm.c')
-rw-r--r--gcc/config/arm/arm.c49
1 files changed, 40 insertions, 9 deletions
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index ed41888..e1b5be2 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -366,6 +366,9 @@ int arm_arch3m = 0;
/* Nonzero if this chip supports the ARM Architecture 4 extensions. */
int arm_arch4 = 0;
+/* Nonzero if this chip supports the ARM Architecture 4t extensions. */
+int arm_arch4t = 0;
+
/* Nonzero if this chip supports the ARM Architecture 5 extensions. */
int arm_arch5 = 0;
@@ -802,6 +805,7 @@ arm_override_options (void)
/* Initialize boolean versions of the flags, for use in the arm.md file. */
arm_arch3m = (insn_flags & FL_ARCH3M) != 0;
arm_arch4 = (insn_flags & FL_ARCH4) != 0;
+ arm_arch4t = arm_arch4 & ((insn_flags & FL_THUMB) != 0);
arm_arch5 = (insn_flags & FL_ARCH5) != 0;
arm_arch5e = (insn_flags & FL_ARCH5E) != 0;
arm_arch6 = (insn_flags & FL_ARCH6) != 0;
@@ -816,6 +820,11 @@ arm_override_options (void)
arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
+ /* V5 code we generate is completely interworking capable, so we turn off
+ TARGET_INTERWORK here to avoid many tests later on. */
+ if (arm_arch5)
+ target_flags &= ~ARM_FLAG_INTERWORK;
+
if (target_abi_name)
{
for (i = 0; i < ARRAY_SIZE (arm_all_abis); i++)
@@ -8000,8 +8009,10 @@ vfp_emit_fstmx (int base_reg, int count)
const char *
output_call (rtx *operands)
{
- /* Handle calls to lr using ip (which may be clobbered in subr anyway). */
+ if (arm_arch5)
+ abort (); /* Patterns should call blx <reg> directly. */
+ /* Handle calls to lr using ip (which may be clobbered in subr anyway). */
if (REGNO (operands[0]) == LR_REGNUM)
{
operands[0] = gen_rtx_REG (SImode, IP_REGNUM);
@@ -8010,7 +8021,7 @@ output_call (rtx *operands)
output_asm_insn ("mov%?\t%|lr, %|pc", operands);
- if (TARGET_INTERWORK)
+ if (TARGET_INTERWORK || arm_arch4t)
output_asm_insn ("bx%?\t%0", operands);
else
output_asm_insn ("mov%?\t%|pc, %0", operands);
@@ -8022,7 +8033,7 @@ output_call (rtx *operands)
const char *
output_call_mem (rtx *operands)
{
- if (TARGET_INTERWORK)
+ if (TARGET_INTERWORK && !arm_arch5)
{
output_asm_insn ("ldr%?\t%|ip, %0", operands);
output_asm_insn ("mov%?\t%|lr, %|pc", operands);
@@ -8034,8 +8045,16 @@ output_call_mem (rtx *operands)
first instruction. It's safe to use IP as the target of the
load since the call will kill it anyway. */
output_asm_insn ("ldr%?\t%|ip, %0", operands);
- output_asm_insn ("mov%?\t%|lr, %|pc", operands);
- output_asm_insn ("mov%?\t%|pc, %|ip", operands);
+ if (arm_arch5)
+ output_asm_insn ("blx%?%|ip", operands);
+ else
+ {
+ output_asm_insn ("mov%?\t%|lr, %|pc", operands);
+ if (arm_arch4t)
+ output_asm_insn ("bx%?\t%|ip", operands);
+ else
+ output_asm_insn ("mov%?\t%|pc, %|ip", operands);
+ }
}
else
{
@@ -9261,9 +9280,8 @@ output_return_instruction (rtx operand, int really_return, int reverse)
break;
default:
- /* ARMv5 implementations always provide BX, so interworking
- is the default. */
- if ((insn_flags & FL_ARCH5) != 0)
+ /* Use bx if it's available. */
+ if (arm_arch5 || arm_arch4t)
sprintf (instr, "bx%s\t%%|lr", conditional);
else
sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
@@ -9729,7 +9747,10 @@ arm_output_epilogue (rtx sibling)
break;
default:
- asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
+ if (arm_arch5 || arm_arch4t)
+ asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
+ else
+ asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
break;
}
@@ -11234,6 +11255,16 @@ arm_final_prescan_insn (rtx insn)
break;
case CALL_INSN:
+ /* The AAPCS says that conditional calls should not be
+ used since they make interworking inefficient (the
+ linker can't transform BL<cond> into BLX). That's
+ only a problem if the machine has BLX. */
+ if (arm_arch5)
+ {
+ fail = TRUE;
+ break;
+ }
+
/* Succeed if the following insn is the target label, or
if the following two insns are a barrier and the
target label. */