Fix PR target/19599 - tailcall function pointers.
authorRamana Radhakrishnan <ramana.radhakrishnan@arm.com>
Wed, 15 May 2013 11:49:06 +0000 (11:49 +0000)
committerRamana Radhakrishnan <ramana@gcc.gnu.org>
Wed, 15 May 2013 11:49:06 +0000 (11:49 +0000)
2013-05-15  Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>

PR target/19599
* config/arm/predicates.md (call_insn_operand): New predicate.
* config/arm/constraints.md ("Cs", "Ss"):  New constraints.
* config/arm/arm.md (*call_insn, *call_value_insn): Match only
if insn is not a tail call.
(*sibcall_insn, *sibcall_value_insn): Adjust for tailcalling through
registers.
* config/arm/arm.h (enum reg_class): New caller save register class.
(REG_CLASS_NAMES): Likewise.
(REG_CLASS_CONTENTS): Likewise.
* config/arm/arm.c (arm_function_ok_for_sibcall): Allow tailcalling
without decls.

2013-05-15  Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>

PR target/19599
* gcc.target/arm/pr40887.c: Adjust testcase.
* gcc.target/arm/pr19599.c: New test.

From-SVN: r198928

gcc/ChangeLog
gcc/config/arm/arm.c
gcc/config/arm/arm.h
gcc/config/arm/arm.md
gcc/config/arm/constraints.md
gcc/config/arm/predicates.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/pr19599.c [new file with mode: 0644]
gcc/testsuite/gcc.target/arm/pr40887.c

index e0c5c322b72522e3b2f0f214cee0b1d3cc6507d0..4b6c6038989c9189df3e98850e01d4c99bd69f74 100644 (file)
@@ -1,3 +1,18 @@
+2013-05-15  Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>
+
+       PR target/19599
+       * config/arm/predicates.md (call_insn_operand): New predicate.
+       * config/arm/constraints.md ("Cs", "Ss"):  New constraints.
+       * config/arm/arm.md (*call_insn, *call_value_insn): Match only
+       if insn is not a tail call.
+       (*sibcall_insn, *sibcall_value_insn): Adjust for tailcalling through
+       registers.
+       * config/arm/arm.h (enum reg_class): New caller save register class.
+       (REG_CLASS_NAMES): Likewise.
+       (REG_CLASS_CONTENTS): Likewise.
+       * config/arm/arm.c (arm_function_ok_for_sibcall): Allow tailcalling
+       without decls.
+
 2013-05-15  Richard Biener  <rguenther@suse.de>
 
        * tree-vect-loop.c (vect_transform_loop): Use MSG_NOTE instead
index 170dcb7042852977f9a7f98bad2228e1bf693e37..036db8ab6fb28779d251fb7b3b3e2541ab72c681 100644 (file)
@@ -5376,9 +5376,8 @@ arm_function_ok_for_sibcall (tree decl, tree exp)
   if (cfun->machine->sibcall_blocked)
     return false;
 
-  /* Never tailcall something for which we have no decl, or if we
-     are generating code for Thumb-1.  */
-  if (decl == NULL || TARGET_THUMB1)
+  /* Never tailcall something if we are generating code for Thumb-1.  */
+  if (TARGET_THUMB1)
     return false;
 
   /* The PIC register is live on entry to VxWorks PLT entries, so we
@@ -5388,13 +5387,14 @@ arm_function_ok_for_sibcall (tree decl, tree exp)
 
   /* Cannot tail-call to long calls, since these are out of range of
      a branch instruction.  */
-  if (arm_is_long_call_p (decl))
+  if (decl && arm_is_long_call_p (decl))
     return false;
 
   /* If we are interworking and the function is not declared static
      then we can't tail-call it unless we know that it exists in this
      compilation unit (since it might be a Thumb routine).  */
-  if (TARGET_INTERWORK && TREE_PUBLIC (decl) && !TREE_ASM_WRITTEN (decl))
+  if (TARGET_INTERWORK && decl && TREE_PUBLIC (decl)
+      && !TREE_ASM_WRITTEN (decl))
     return false;
 
   func_type = arm_current_func_type ();
index 46450b3544010d9f09ac397909c410d5d0442efd..3a49a90c184246f71957fb84bdc64d64ecc7e78d 100644 (file)
@@ -1142,6 +1142,7 @@ enum reg_class
   STACK_REG,
   BASE_REGS,
   HI_REGS,
+  CALLER_SAVE_REGS,
   GENERAL_REGS,
   CORE_REGS,
   VFP_D0_D7_REGS,
@@ -1168,6 +1169,7 @@ enum reg_class
   "STACK_REG",         \
   "BASE_REGS",         \
   "HI_REGS",           \
+  "CALLER_SAVE_REGS",  \
   "GENERAL_REGS",      \
   "CORE_REGS",         \
   "VFP_D0_D7_REGS",    \
@@ -1193,6 +1195,7 @@ enum reg_class
   { 0x00002000, 0x00000000, 0x00000000, 0x00000000 }, /* STACK_REG */  \
   { 0x000020FF, 0x00000000, 0x00000000, 0x00000000 }, /* BASE_REGS */  \
   { 0x00005F00, 0x00000000, 0x00000000, 0x00000000 }, /* HI_REGS */    \
+  { 0x0000100F, 0x00000000, 0x00000000, 0x00000000 }, /* CALLER_SAVE_REGS */ \
   { 0x00005FFF, 0x00000000, 0x00000000, 0x00000000 }, /* GENERAL_REGS */ \
   { 0x00007FFF, 0x00000000, 0x00000000, 0x00000000 }, /* CORE_REGS */  \
   { 0xFFFF0000, 0x00000000, 0x00000000, 0x00000000 }, /* VFP_D0_D7_REGS  */ \
index 06b3c18a7f4a54747d52317b5d4a78fb0d44d478..d3bc760952dcd13e70769c9e49b825c1261101a7 100644 (file)
          (match_operand 1 "" ""))
    (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_ARM && arm_arch5"
+  "TARGET_ARM && arm_arch5 && !SIBLING_CALL_P (insn)"
   "blx%?\\t%0"
   [(set_attr "type" "call")]
 )
          (match_operand 1 "" ""))
    (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_ARM && !arm_arch5"
+  "TARGET_ARM && !arm_arch5 && !SIBLING_CALL_P (insn)"
   "*
   return output_call (operands);
   "
         (match_operand 1 "" ""))
    (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_ARM && !arm_arch5"
+  "TARGET_ARM && !arm_arch5 && !SIBLING_CALL_P (insn)"
   "*
   return output_call_mem (operands);
   "
         (match_operand 1 "" ""))
    (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_THUMB1 && arm_arch5"
+  "TARGET_THUMB1 && arm_arch5 && !SIBLING_CALL_P (insn)"
   "blx\\t%0"
   [(set_attr "length" "2")
    (set_attr "type" "call")]
         (match_operand 1 "" ""))
    (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_THUMB1 && !arm_arch5"
+  "TARGET_THUMB1 && !arm_arch5 && !SIBLING_CALL_P (insn)"
   "*
   {
     if (!TARGET_CALLER_INTERWORKING)
              (match_operand 2 "" "")))
    (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_ARM && arm_arch5"
+  "TARGET_ARM && arm_arch5 && !SIBLING_CALL_P (insn)"
   "blx%?\\t%1"
   [(set_attr "type" "call")]
 )
              (match_operand 2 "" "")))
    (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_ARM && !arm_arch5"
+  "TARGET_ARM && !arm_arch5 && !SIBLING_CALL_P (insn)"
   "*
   return output_call (&operands[1]);
   "
              (match_operand 2 "" "")))
    (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
-  "TARGET_ARM && !arm_arch5 && (!CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))"
+  "TARGET_ARM && !arm_arch5 && (!CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
+   && !SIBLING_CALL_P (insn)"
   "*
   return output_call_mem (&operands[1]);
   "
    (use (match_operand 2 "" ""))
    (clobber (reg:SI LR_REGNUM))]
   "TARGET_32BIT
+   && !SIBLING_CALL_P (insn)
    && (GET_CODE (operands[0]) == SYMBOL_REF)
    && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[0]))"
   "*
    (use (match_operand 3 "" ""))
    (clobber (reg:SI LR_REGNUM))]
   "TARGET_32BIT
+   && !SIBLING_CALL_P (insn)
    && (GET_CODE (operands[1]) == SYMBOL_REF)
    && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[1]))"
   "*
   "TARGET_32BIT"
   "
   {
+    if (!REG_P (XEXP (operands[0], 0))
+       && (GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF))
+     XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0));
+
     if (operands[2] == NULL_RTX)
       operands[2] = const0_rtx;
   }"
   "TARGET_32BIT"
   "
   {
+    if (!REG_P (XEXP (operands[1], 0)) &&
+       (GET_CODE (XEXP (operands[1],0)) != SYMBOL_REF))
+     XEXP (operands[1], 0) = force_reg (SImode, XEXP (operands[1], 0));
+
     if (operands[3] == NULL_RTX)
       operands[3] = const0_rtx;
   }"
 )
 
 (define_insn "*sibcall_insn"
- [(call (mem:SI (match_operand:SI 0 "" "X"))
+ [(call (mem:SI (match_operand:SI 0 "call_insn_operand" "Cs,Ss"))
        (match_operand 1 "" ""))
   (return)
   (use (match_operand 2 "" ""))]
-  "TARGET_32BIT && GET_CODE (operands[0]) == SYMBOL_REF"
+  "TARGET_32BIT && SIBLING_CALL_P (insn)"
   "*
-  return NEED_PLT_RELOC ? \"b%?\\t%a0(PLT)\" : \"b%?\\t%a0\";
+  if (which_alternative == 1)
+    return NEED_PLT_RELOC ? \"b%?\\t%a0(PLT)\" : \"b%?\\t%a0\";
+  else
+    {
+      if (arm_arch5 || arm_arch4t)
+       return \" bx\\t%0\\t%@ indirect register sibling call\";
+      else
+       return \"mov%?\\t%|pc, %0\\t%@ indirect register sibling call\";
+    }
   "
   [(set_attr "type" "call")]
 )
 
 (define_insn "*sibcall_value_insn"
- [(set (match_operand 0 "" "")
-       (call (mem:SI (match_operand:SI 1 "" "X"))
+ [(set (match_operand 0 "s_register_operand" "")
+       (call (mem:SI (match_operand:SI 1 "call_insn_operand" "Cs,Ss"))
             (match_operand 2 "" "")))
   (return)
   (use (match_operand 3 "" ""))]
-  "TARGET_32BIT && GET_CODE (operands[1]) == SYMBOL_REF"
+  "TARGET_32BIT && SIBLING_CALL_P (insn)"
   "*
-  return NEED_PLT_RELOC ? \"b%?\\t%a1(PLT)\" : \"b%?\\t%a1\";
+  if (which_alternative == 1)
+   return NEED_PLT_RELOC ? \"b%?\\t%a1(PLT)\" : \"b%?\\t%a1\";
+  else
+    {
+      if (arm_arch5 || arm_arch4t)
+       return \"bx\\t%1\";
+      else
+       return \"mov%?\\t%|pc, %1\\t@ indirect sibling call \";
+    }
   "
   [(set_attr "type" "call")]
 )
index 767ebfb6080491fb3f5038fb5b8b029d01bd8c88..7e7b3e69e0a5a9e583d77687cacdef26447eb461 100644 (file)
@@ -96,6 +96,9 @@
 (define_register_constraint "c" "CC_REG"
  "@internal The condition code register.")
 
+(define_register_constraint "Cs" "CALLER_SAVE_REGS"
+ "@internal The caller save registers.  Useful for sibcalls.")
+
 (define_constraint "I"
  "In ARM/Thumb-2 state a constant that can be used as an immediate value in a
   Data Processing instruction.  In Thumb-1 state a constant in the range
 ;; Additionally, we used to have a Q constraint in Thumb state, but
 ;; this wasn't really a valid memory constraint.  Again, all uses of
 ;; this now seem to have been removed.
+
+(define_constraint "Ss"
+ "@internal
+  Ss is a symbol reference."
+ (match_code "symbol_ref")
+)
index 2e0de08a8d022aae3a1d4b8d3ad037d32e2fdb7a..92de9fe8bd9407064b78e9a7c521bc629a32a630 100644 (file)
 (define_predicate "mem_noofs_operand"
   (and (match_code "mem")
        (match_code "reg" "0")))
+
+(define_predicate "call_insn_operand"
+  (ior (match_code "symbol_ref")
+       (match_operand 0 "s_register_operand")))
index 984ee6d5b17de9bf5298eaa40c6e43803515d5ed..d69fbd4e74f39925fb811ac47f94199d892fd3ed 100644 (file)
@@ -1,3 +1,9 @@
+2013-05-15  Ramana Radhakrishnan  <ramana.radhakrishnan@arm.com>
+
+       PR target/19599
+       * gcc.target/arm/pr40887.c: Adjust testcase.
+       * gcc.target/arm/pr19599.c: New test.
+
 2013-05-15  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/57275
diff --git a/gcc/testsuite/gcc.target/arm/pr19599.c b/gcc/testsuite/gcc.target/arm/pr19599.c
new file mode 100644 (file)
index 0000000..e3e066c
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-skip-if "need at least armv5te" { *-*-* } { "-march=armv[234]*" } { "" } } */
+/* { dg-options "-O2 -march=armv5te -marm" }  */
+/* { dg-final { scan-assembler "bx" } } */
+
+int (*indirect_func)();
+
+int indirect_call()
+{
+  return indirect_func();
+}
index 0b5e873a5c9fefdb7792d2173490f88c33ff29cb..5cabe3ab7feaa2563702adb494bcfbeeff956053 100644 (file)
@@ -2,9 +2,9 @@
 /* { dg-options "-O2 -march=armv5te" }  */
 /* { dg-final { scan-assembler "blx" } } */
 
-int (*indirect_func)();
+int (*indirect_func)(int x);
 
 int indirect_call()
 {
-    return indirect_func();
+  return indirect_func(20) + indirect_func (40);
 }