From 68d560d4d612ad0683bae7b36708ef88685316c5 Mon Sep 17 00:00:00 2001 From: Richard Earnshaw Date: Fri, 25 Jun 2004 10:42:21 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 21 ++++++++++++ gcc/config/arm/arm.c | 49 ++++++++++++++++++++++----- gcc/config/arm/arm.h | 3 ++ gcc/config/arm/arm.md | 93 ++++++++++++++++++++++++++++++++++++++------------- 4 files changed, 133 insertions(+), 33 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 80c7a80..343d785 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2004-06-25 Richard Earnshaw + + * 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. + 2004-06-25 Richard Sandiford * config/mips/mips.c (reg_or_const_float_1_operand): Reimplement 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 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 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. */ diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 736934b..d6d07e6 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -490,6 +490,9 @@ extern int arm_arch3m; /* Nonzero if this chip supports the ARM Architecture 4 extensions. */ extern int arm_arch4; +/* Nonzero if this chip supports the ARM Architecture 4T extensions. */ +extern int arm_arch4t; + /* Nonzero if this chip supports the ARM Architecture 5 extensions. */ extern int arm_arch5; diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index fb13fe0..4b94f6e 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -7377,12 +7377,22 @@ }" ) -(define_insn "*call_reg" +(define_insn "*call_reg_armv5" [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r")) (match_operand 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_ARM" + "TARGET_ARM && arm_arch5" + "blx%?\\t%0" + [(set_attr "type" "call")] +) + +(define_insn "*call_reg_arm" + [(call (mem:SI (match_operand:SI 0 "s_register_operand" "r")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (clobber (reg:SI LR_REGNUM))] + "TARGET_ARM && !arm_arch5" "* return output_call (operands); " @@ -7404,35 +7414,29 @@ (set_attr "type" "call")] ) -(define_insn "*call_indirect" +(define_insn "*call_reg_thumb_v5" [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) (match_operand 1 "" "")) (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_THUMB" - "* - { - if (TARGET_CALLER_INTERWORKING) - return \"bl\\t%__interwork_call_via_%0\"; - else - return \"bl\\t%__call_via_%0\"; - }" - [(set_attr "type" "call")] + "TARGET_THUMB && arm_arch5" + "blx\\t%0" + [(set_attr "length" "2") + (set_attr "type" "call")] ) -(define_insn "*call_value_indirect" - [(set (match_operand 0 "" "") - (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) - (match_operand 2 "" ""))) - (use (match_operand 3 "" "")) +(define_insn "*call_reg_thumb" + [(call (mem:SI (match_operand:SI 0 "register_operand" "l*r")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_THUMB" + "TARGET_THUMB && !arm_arch5" "* { if (TARGET_CALLER_INTERWORKING) - return \"bl\\t%__interwork_call_via_%1\"; + return \"bl\\t%__interwork_call_via_%0\"; else - return \"bl\\t%__call_via_%1\"; + return \"bl\\t%__call_via_%0\"; }" [(set_attr "type" "call")] ) @@ -7459,13 +7463,24 @@ }" ) -(define_insn "*call_value_reg" +(define_insn "*call_value_reg_armv5" [(set (match_operand 0 "" "") (call (mem:SI (match_operand:SI 1 "s_register_operand" "r")) (match_operand 2 "" ""))) (use (match_operand 3 "" "")) (clobber (reg:SI LR_REGNUM))] - "TARGET_ARM" + "TARGET_ARM && arm_arch5" + "blx%?\\t%1" + [(set_attr "type" "call")] +) + +(define_insn "*call_value_reg_arm" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "s_register_operand" "r")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (reg:SI LR_REGNUM))] + "TARGET_ARM && !arm_arch5" "* return output_call (&operands[1]); " @@ -7487,6 +7502,35 @@ (set_attr "type" "call")] ) +(define_insn "*call_value_reg_thumb_v5" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (reg:SI LR_REGNUM))] + "TARGET_THUMB && arm_arch5" + "blx\\t%1" + [(set_attr "length" "2") + (set_attr "type" "call")] +) + +(define_insn "*call_value_reg_thumb" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "register_operand" "l*r")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (reg:SI LR_REGNUM))] + "TARGET_THUMB && !arm_arch5" + "* + { + if (TARGET_CALLER_INTERWORKING) + return \"bl\\t%__interwork_call_via_%1\"; + else + return \"bl\\t%__call_via_%1\"; + }" + [(set_attr "type" "call")] +) + ;; Allow calls to SYMBOL_REFs specially as they are not valid general addresses ;; The 'a' causes the operand to be treated as an address, i.e. no '#' output. @@ -7786,6 +7830,7 @@ "" ) +;; NB Never uses BX. (define_insn "*arm_indirect_jump" [(set (pc) (match_operand:SI 0 "s_register_operand" "r"))] @@ -7794,8 +7839,6 @@ [(set_attr "predicable" "yes")] ) -;; Although not supported by the define_expand above, -;; cse/combine may generate this form. (define_insn "*load_indirect_jump" [(set (pc) (match_operand:SI 0 "memory_operand" "m"))] @@ -7807,6 +7850,7 @@ (set_attr "predicable" "yes")] ) +;; NB Never uses BX. (define_insn "*thumb_indirect_jump" [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))] @@ -10099,6 +10143,7 @@ " ) +;; NB never uses BX. (define_insn "*thumb_tablejump" [(set (pc) (match_operand:SI 0 "register_operand" "l*r")) (use (label_ref (match_operand 1 "" "")))] -- 2.7.4