diff mbox

[ARM] PR target/68214: Delete IP-reg-clobbering call-through-mem patterns

Message ID 56615C8E.8090307@arm.com
State Accepted
Commit dcc75da43515e127740c04314c831e1e51453775
Headers show

Commit Message

Kyrylo Tkachov Dec. 4, 2015, 9:27 a.m. UTC
Hi all,

The wrong-code in this PR occurs for pre-ARMv5 architectures with Thumb interworking when trying
to use a static chain. Our output_call_mem function that outputs the assembly for the call explicitly
clobbers the IP register, which is also used as the static chain register.

Richard suggested offline that we can just remove the *call_mem and *call_value_mem patterns as they
are of no use anymore and just cause us trouble such as this.  The midend does a good enough job of
figuring out it has to load the address to which we should branch.

So this patch does that. It's an entirely negative diffstat :)
For the failing testcase gcc.dg/cwsc1.c the bad code before this patch in the main function is:
     mov    ip, r4
     ldr    r3, .L6
     ldr    ip, [r3]
     mov    lr, pc
     bx    ip

and with this patch it is:
     ldr    r3, .L6
     ldr    r3, [r3]
     mov    ip, r4
     mov    lr, pc
     bx    r3

As you can see it's correct and no less efficient than before.

Bootstrapped and tested on arm-none-linux-gnueabihf and a test run with -mcpu=arm7tdmi didn't show any problems.

Ok for trunk?

Thanks,
Kyrill

2015-12-04  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>

     PR target/68214
     * config/arm/arm.md (*call_mem): Delete pattern.
     (*call_value_mem): Likewise.
     * config/arm/arm.c (output_call_mem): Delete.
     * config/arm/arm-protos.h (output_call_mem): Delete prototype.
diff mbox

Patch

diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index e4b8fb3feda74d60e7f6628bb51b9d6d6a431e54..e7328e79650739fca1c3e21b10c194feaa697465 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -132,7 +132,6 @@  extern bool arm_const_double_by_parts (rtx);
 extern bool arm_const_double_by_immediates (rtx);
 extern void arm_emit_call_insn (rtx, rtx, bool);
 extern const char *output_call (rtx *);
-extern const char *output_call_mem (rtx *);
 void arm_emit_movpair (rtx, rtx);
 extern const char *output_mov_long_double_arm_from_arm (rtx *);
 extern const char *output_move_double (rtx *, bool, int *count);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index c1cfe83d3f0716837fd3f59399a0f6a92f33c67c..f822a92d2684030c60271cfd74a81772b096e151 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -18057,41 +18057,6 @@  output_call (rtx *operands)
   return "";
 }
 
-/* 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)
-{
-  gcc_assert (!arm_arch5);
-  if (TARGET_INTERWORK)
-    {
-      output_asm_insn ("ldr%?\t%|ip, %0", operands);
-      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
-      output_asm_insn ("bx%?\t%|ip", operands);
-    }
-  else if (regno_use_in (LR_REGNUM, operands[0]))
-    {
-      /* LR is used in the memory address.  We load the address in the
-	 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);
-      if (arm_arch4t)
-	output_asm_insn ("bx%?\t%|ip", operands);
-      else
-	output_asm_insn ("mov%?\t%|pc, %|ip", operands);
-    }
-  else
-    {
-      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
-      output_asm_insn ("ldr%?\t%|pc, %0", operands);
-    }
-
-  return "";
-}
-
-
 /* Output a move from arm registers to arm registers of a long double
    OPERANDS[0] is the destination.
    OPERANDS[1] is the source.  */
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 2dcd2ccf6dbc476dedeaacdd5bb906a040d1617c..2b48bbaf034b286d723536ec2aa6fe0f9b312911 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -7709,23 +7709,6 @@  (define_insn "*call_reg_arm"
 )
 
 
-;; 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 && !arm_arch5 && !SIBLING_CALL_P (insn)"
-  "*
-  return output_call_mem (operands);
-  "
-  [(set_attr "length" "12")
-   (set_attr "type" "call")]
-)
-
 (define_expand "call_value"
   [(parallel [(set (match_operand       0 "" "")
 	           (call (match_operand 1 "memory_operand" "")
@@ -7789,23 +7772,6 @@  (define_insn "*call_value_reg_arm"
    (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 && !arm_arch5 && (!CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
-   && !SIBLING_CALL_P (insn)"
-  "*
-  return output_call_mem (&operands[1]);
-  "
-  [(set_attr "length" "12")
-   (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.