Current, indirect function call prevents tail-call optimization on AArch64.

This patch adapt the fix for PR arm/19599 to AArch64.

Is it ok for next stage 1?

Thanks.

-- Jiong

gcc/

* config/aarch64/predicates.md (aarch64_call_insn_operand): New predicate.
    * config/aarch64/constraints.md ("Ucs", "Usf"):  New constraints.
* config/aarch64/aarch64.md (*sibcall_insn, *sibcall_value_insn): Adjust for
    tailcalling through registers.
* config/aarch64/aarch64.h (enum reg_class): New caller save register class.
    (REG_CLASS_NAMES): Likewise.
    (REG_CLASS_CONTENTS): Likewise.
* config/aarch64/aarch64.c (aarch64_function_ok_for_sibcall): Allow tailcalling
    without decls.

gcc/testsuite

    *gcc.target/aarch64/tail-indirect-call.c: New test.

diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 901ad3d..fd93554 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -1168,16 +1168,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm)
 static bool
 aarch64_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
-  /* Indirect calls are not currently supported.  */
-  if (decl == NULL)
-    return false;
-
-  /* Cannot tail-call to long-calls, since these are outside of the
-     range of a branch instruction (we could handle this if we added
-     support for indirect tail-calls.  */
-  if (aarch64_decl_is_long_call_p (decl))
-    return false;
-
+  /* Currently, always true.  */
   return true;
 }
 
@@ -4255,6 +4246,7 @@ aarch64_class_max_nregs (reg_class_t regclass, enum machine_mode mode)
   switch (regclass)
     {
     case CORE_REGS:
+    case CALLER_SAVE_REGS:
     case POINTER_REGS:
     case GENERAL_REGS:
     case ALL_REGS:
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index 13c424c..6911206 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -407,6 +407,7 @@ enum reg_class
 {
   NO_REGS,
   CORE_REGS,
+  CALLER_SAVE_REGS,
   GENERAL_REGS,
   STACK_REG,
   POINTER_REGS,
@@ -422,6 +423,7 @@ enum reg_class
 {						\
   "NO_REGS",					\
   "CORE_REGS",					\
+  "CALLER_SAVE_REGS",				\
   "GENERAL_REGS",				\
   "STACK_REG",					\
   "POINTER_REGS",				\
@@ -434,6 +436,7 @@ enum reg_class
 {									\
   { 0x00000000, 0x00000000, 0x00000000 },	/* NO_REGS */		\
   { 0x7fffffff, 0x00000000, 0x00000003 },	/* CORE_REGS */		\
+  { 0x0007ffff, 0x00000000, 0x00000000 },	/* CALLER_SAVE_REGS */	\
   { 0x7fffffff, 0x00000000, 0x00000003 },	/* GENERAL_REGS */	\
   { 0x80000000, 0x00000000, 0x00000000 },	/* STACK_REG */		\
   { 0xffffffff, 0x00000000, 0x00000003 },	/* POINTER_REGS */	\
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 99a6ac8..f30b444 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -513,6 +513,10 @@
 	      (use (match_operand 2 "" ""))])]
   ""
   {
+    if (!REG_P (XEXP (operands[0], 0))
+       && (GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF))
+     XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0));
+
     if (operands[2] == NULL_RTX)
       operands[2] = const0_rtx;
   }
@@ -526,30 +530,37 @@
 	      (use (match_operand 3 "" ""))])]
   ""
   {
+    if (!REG_P (XEXP (operands[1], 0))
+       && (GET_CODE (XEXP (operands[1], 0)) != SYMBOL_REF))
+     XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0));
+
     if (operands[3] == NULL_RTX)
       operands[3] = const0_rtx;
   }
 )
 
 (define_insn "*sibcall_insn"
-  [(call (mem:DI (match_operand:DI 0 "" "X"))
+  [(call (mem:DI (match_operand:DI 0 "aarch64_call_insn_operand" "Ucs,Usf"))
 	 (match_operand 1 "" ""))
    (return)
    (use (match_operand 2 "" ""))]
-  "GET_CODE (operands[0]) == SYMBOL_REF"
-  "b\\t%a0"
+  "SIBLING_CALL_P (insn)"
+  "@
+   br\\t%0
+   b\\t%a0"
   [(set_attr "type" "branch")]
-
 )
 
 (define_insn "*sibcall_value_insn"
   [(set (match_operand 0 "" "")
-	(call (mem:DI (match_operand 1 "" "X"))
+	(call (mem:DI (match_operand 1 "aarch64_call_insn_operand" "Ucs,Usf"))
 	      (match_operand 2 "" "")))
    (return)
    (use (match_operand 3 "" ""))]
-  "GET_CODE (operands[1]) == SYMBOL_REF"
-  "b\\t%a1"
+  "SIBLING_CALL_P (insn)"
+  "@
+   br\\t%1
+   b\\t%a1"
   [(set_attr "type" "branch")]
 )
 
diff --git a/gcc/config/aarch64/constraints.md b/gcc/config/aarch64/constraints.md
index 12ab570..244f97d 100644
--- a/gcc/config/aarch64/constraints.md
+++ b/gcc/config/aarch64/constraints.md
@@ -92,6 +92,14 @@
   (and (match_code "const_int")
        (match_test "(unsigned HOST_WIDE_INT) ival < 64")))
 
+(define_register_constraint "Ucs" "CALLER_SAVE_REGS"
+ "@internal The caller save registers.  Useful for sibcalls.")
+
+(define_constraint "Usf"
+ "@internal Usf is a symbol reference."
+ (match_code "symbol_ref")
+)
+
 (define_constraint "UsM"
   "@internal
   A constraint that matches the immediate constant -1."
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index c8e27d8..2702a3c 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -26,6 +26,10 @@
 			      && GET_MODE_CLASS (GET_MODE (op)) == MODE_CC"))))
 )
 
+(define_predicate "aarch64_call_insn_operand"
+  (ior (match_code "symbol_ref")
+       (match_operand 0 "register_operand")))
+
 (define_predicate "aarch64_simd_register"
   (and (match_code "reg")
        (ior (match_test "REGNO_REG_CLASS (REGNO (op)) == FP_LO_REGS")
diff --git a/gcc/testsuite/gcc.target/aarch64/tail-indirect-call.c b/gcc/testsuite/gcc.target/aarch64/tail-indirect-call.c
new file mode 100644
index 0000000..057ae3e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/tail-indirect-call.c
@@ -0,0 +1,8 @@
+/* { dg-do compile }  */
+/* { dg-options "-O2" }  */
+
+typedef void FP(int);
+/* { dg-final { scan-assembler "br" } } */
+/* { dg-final { scan-assembler-not "blr" } } */
+void f1(FP fp, int n) { (fp)(n); }
+void f2(int n, FP fp) { (fp)(n); }

Reply via email to