arm.c (arm_arch4t): New variable.
authorRichard Earnshaw <rearnsha@arm.com>
Fri, 25 Jun 2004 10:42:21 +0000 (10:42 +0000)
committerRichard Earnshaw <rearnsha@gcc.gnu.org>
Fri, 25 Jun 2004 10:42:21 +0000 (10:42 +0000)
* 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
gcc/config/arm/arm.c
gcc/config/arm/arm.h
gcc/config/arm/arm.md

index 80c7a802501bc361787a6ee654e51df127c3320e..343d785ed6b5d00712c2eb3e1b3f9b1730babc3f 100644 (file)
@@ -1,3 +1,24 @@
+2004-06-25  Richard Earnshaw  <rearnsha@arm.com>
+
+       * 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  <rsandifo@redhat.com>
 
        * config/mips/mips.c (reg_or_const_float_1_operand): Reimplement
index ed4188801351a049a5665753282c37127449e544..e1b5be2e9a295d361cd68fec7cf6922014b74f01 100644 (file)
@@ -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.  */
index 736934b35a49a5b53ede960fc15d6dd9f8f6072e..d6d07e6721940f2007deab36cf33caca320db503 100644 (file)
@@ -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;
 
index fb13fe061f54b508213745d4a8aef0cec2ba69e5..4b94f6e90f33aecac8259be06298f9333262a1e8 100644 (file)
   }"
 )
 
-(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);
   "
    (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")]
 )
   }"
 )
 
-(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]);
   "
    (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.
 
   ""
 )
 
+;; NB Never uses BX.
 (define_insn "*arm_indirect_jump"
   [(set (pc)
        (match_operand:SI 0 "s_register_operand" "r"))]
   [(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"))]
    (set_attr "predicable" "yes")]
 )
 
+;; NB Never uses BX.
 (define_insn "*thumb_indirect_jump"
   [(set (pc)
        (match_operand:SI 0 "register_operand" "l*r"))]
   "
 )
 
+;; NB never uses BX.
 (define_insn "*thumb_tablejump"
   [(set (pc) (match_operand:SI 0 "register_operand" "l*r"))
    (use (label_ref (match_operand 1 "" "")))]