From 0986ef456ea9f7cb0a1ba2547690191139bc4dc5 Mon Sep 17 00:00:00 2001
From: Julian Brown <julian@codesourcery.com>
Date: Thu, 24 Dec 2009 10:46:00 +0000
Subject: [PATCH] re PR target/40887 (GCC generates suboptimal code for
 indirect function calls on ARM)

Fix PR target/40887



2009-12-24  Julian Brown  <julian@codesourcery.com>
            Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>

        PR target/40887

        * config/arm/arm.c (output_call_mem): Remove armv5 support.
        * config/arm/arm.md (*call_mem): Disable for armv5. Add note.
        (*call_value_mem): Likewise.


        PR target/40887

        * gcc.target/gcc.arm/pr40887.c: New test.

Co-Authored-By: Ramana Radhakrishnan <ramana.radhakrishnan@arm.com>

From-SVN: r155453
---
 gcc/ChangeLog                          |  8 ++++++++
 gcc/config/arm/arm.c                   | 20 +++++++++-----------
 gcc/config/arm/arm.md                  | 11 +++++++++--
 gcc/testsuite/ChangeLog                |  6 ++++++
 gcc/testsuite/gcc.target/arm/pr40887.c |  9 +++++++++
 5 files changed, 41 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/arm/pr40887.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b1dabd3def05..f7583c26fbc2 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2009-12-24  Julian Brown  <julian@codesourcery.com>
+            Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>
+
+        PR target/40887
+        * config/arm/arm.c (output_call_mem): Remove armv5 support.
+        * config/arm/arm.md (*call_mem): Disable for armv5. Add note.
+        (*call_value_mem): Likewise.
+
 2009-12-23  Jakub Jelinek  <jakub@redhat.com>
 
 	PR rtl-optimization/42475
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index a9ad903e81d4..e9ea2bd1ca0c 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -11772,11 +11772,14 @@ output_call (rtx *operands)
   return "";
 }
 
-/* Output a 'call' insn that is a reference in memory.  */
+/* Output a 'call' insn that is a reference in memory. This is
+   disabled for ARMv5 and we prefer a blx instead because otherwise
+   there's a significant performance overhead.  */
 const char *
 output_call_mem (rtx *operands)
 {
-  if (TARGET_INTERWORK && !arm_arch5)
+  gcc_assert (!arm_arch5);
+  if (TARGET_INTERWORK)
     {
       output_asm_insn ("ldr%?\t%|ip, %0", operands);
       output_asm_insn ("mov%?\t%|lr, %|pc", operands);
@@ -11788,16 +11791,11 @@ 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);
-      if (arm_arch5)
-	output_asm_insn ("blx%?\t%|ip", operands);
+      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
+      if (arm_arch4t)
+	output_asm_insn ("bx%?\t%|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);
-	}
+	output_asm_insn ("mov%?\t%|pc, %|ip", operands);
     }
   else
     {
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index e79ef15fa7d5..cbb0a1bdf143 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -8453,12 +8453,17 @@
    (set_attr "type" "call")]
 )
 
+
+;; Note: not used for armv5+ because the sequence used (ldr pc, ...) is not
+;; considered a function call by the branch predictor of some cores (PR40887).
+;; Falls back to blx rN (*call_reg_armv5).
+
 (define_insn "*call_mem"
   [(call (mem:SI (match_operand:SI 0 "call_memory_operand" "m"))
 	 (match_operand 1 "" ""))
    (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_ARM"
+  "TARGET_ARM && !arm_arch5"
   "*
   return output_call_mem (operands);
   "
@@ -8560,13 +8565,15 @@
    (set_attr "type" "call")]
 )
 
+;; Note: see *call_mem
+
 (define_insn "*call_value_mem"
   [(set (match_operand 0 "" "")
 	(call (mem:SI (match_operand:SI 1 "call_memory_operand" "m"))
 	      (match_operand 2 "" "")))
    (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_ARM && (!CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))"
+  "TARGET_ARM && !arm_arch5 && (!CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))"
   "*
   return output_call_mem (&operands[1]);
   "
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 98d85f4465f9..f2d89276540b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2009-12-24  Julian Brown  <julian@codesourcery.com>
+            Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>
+
+        PR target/40887
+	* gcc.target/arm/pr40887.c: New test.
+
 2009-12-23  Jakub Jelinek  <jakub@redhat.com>
 
 	PR rtl-optimization/42475
diff --git a/gcc/testsuite/gcc.target/arm/pr40887.c b/gcc/testsuite/gcc.target/arm/pr40887.c
new file mode 100644
index 000000000000..ca896fc16669
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr40887.c
@@ -0,0 +1,9 @@
+/* { dg-options "-O2 -march=armv5te" }  */
+/* { dg-final { scan-assembler "blx" } } */
+
+int (*indirect_func)();
+
+int indirect_call()
+{
+    return indirect_func();
+}
-- 
GitLab