diff options
author | Richard Earnshaw <rearnsha@arm.com> | 2004-06-25 10:42:21 +0000 |
---|---|---|
committer | Richard Earnshaw <rearnsha@gcc.gnu.org> | 2004-06-25 10:42:21 +0000 |
commit | 68d560d4d612ad0683bae7b36708ef88685316c5 (patch) | |
tree | 7fbbce5dce641445636037d4f40a6ff09f75b128 /gcc/config/arm/arm.c | |
parent | 576df3214c16163b65f82064f035fd375d0c02aa (diff) | |
download | gcc-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.c | 49 |
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. */ |