[backport gcc-4.9/trunk r198928 <mikpe@it.uu.se>]

gcc/

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.

gcc/testsuite/

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.

--- gcc-4.8.0/gcc/config/arm/arm.c.~1~	2013-03-11 12:48:34.000000000 +0100
+++ gcc-4.8.0/gcc/config/arm/arm.c	2013-05-25 12:44:28.513538225 +0200
@@ -5335,9 +5335,8 @@ arm_function_ok_for_sibcall (tree decl,
   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
@@ -5347,13 +5346,14 @@ arm_function_ok_for_sibcall (tree decl,
 
   /* 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 ();
--- gcc-4.8.0/gcc/config/arm/arm.h.~1~	2013-03-17 17:28:55.000000000 +0100
+++ gcc-4.8.0/gcc/config/arm/arm.h	2013-05-25 12:44:28.513538225 +0200
@@ -1130,6 +1130,7 @@ enum reg_class
   STACK_REG,
   BASE_REGS,
   HI_REGS,
+  CALLER_SAVE_REGS,
   GENERAL_REGS,
   CORE_REGS,
   VFP_D0_D7_REGS,
@@ -1156,6 +1157,7 @@ enum reg_class
   "STACK_REG",		\
   "BASE_REGS",		\
   "HI_REGS",		\
+  "CALLER_SAVE_REGS",	\
   "GENERAL_REGS",	\
   "CORE_REGS",		\
   "VFP_D0_D7_REGS",	\
@@ -1181,6 +1183,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  */ \
--- gcc-4.8.0/gcc/config/arm/arm.md.~1~	2013-02-22 15:23:12.000000000 +0100
+++ gcc-4.8.0/gcc/config/arm/arm.md	2013-05-25 12:44:28.513538225 +0200
@@ -8255,7 +8255,7 @@ (define_insn "*call_reg_armv5"
          (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")]
 )
@@ -8265,7 +8265,7 @@ (define_insn "*call_reg_arm"
          (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);
   "
@@ -8284,7 +8284,7 @@ (define_insn "*call_mem"
 	 (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);
   "
@@ -8297,7 +8297,7 @@ (define_insn "*call_reg_thumb1_v5"
 	 (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")]
@@ -8308,7 +8308,7 @@ (define_insn "*call_reg_thumb1"
 	 (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)
@@ -8367,7 +8367,7 @@ (define_insn "*call_value_reg_armv5"
 	      (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")]
 )
@@ -8378,7 +8378,7 @@ (define_insn "*call_value_reg_arm"
 	      (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]);
   "
@@ -8394,7 +8394,8 @@ (define_insn "*call_value_mem"
 	      (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]);
   "
@@ -8444,6 +8445,7 @@ (define_insn "*call_symbol"
    (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]))"
   "*
@@ -8460,6 +8462,7 @@ (define_insn "*call_value_symbol"
    (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]))"
   "*
@@ -8505,6 +8508,10 @@ (define_expand "sibcall"
   "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;
   }"
@@ -8519,32 +8526,52 @@ (define_expand "sibcall_value"
   "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")]
 )
--- gcc-4.8.0/gcc/config/arm/constraints.md.~1~	2013-01-10 21:38:27.000000000 +0100
+++ gcc-4.8.0/gcc/config/arm/constraints.md	2013-05-25 12:44:28.513538225 +0200
@@ -93,6 +93,9 @@ (define_register_constraint "b" "TARGET_
 (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
@@ -391,3 +394,9 @@ (define_memory_constraint "Uw"
 ;; 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")
+)
--- gcc-4.8.0/gcc/config/arm/predicates.md.~1~	2013-01-10 21:38:27.000000000 +0100
+++ gcc-4.8.0/gcc/config/arm/predicates.md	2013-05-25 12:44:28.513538225 +0200
@@ -617,3 +617,7 @@ (define_special_predicate "add_operator"
 (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")))
--- gcc-4.8.0/gcc/testsuite/gcc.target/arm/pr19599.c.~1~	1970-01-01 01:00:00.000000000 +0100
+++ gcc-4.8.0/gcc/testsuite/gcc.target/arm/pr19599.c	2013-05-25 12:44:28.503538232 +0200
@@ -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();
+}
--- gcc-4.8.0/gcc/testsuite/gcc.target/arm/pr40887.c.~1~	2013-01-17 16:52:19.000000000 +0100
+++ gcc-4.8.0/gcc/testsuite/gcc.target/arm/pr40887.c	2013-05-25 12:44:28.503538232 +0200
@@ -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);
 }
