This is a patch 3 to support the Aarch64 SIMD ABI [1] in GCC.

It defines a new target hook targetm.remove_extra_call_preserved_regs
that takes a rtx_insn and will remove registers from the register
set passed in if we know that this call preserves those registers.
Aarch64 SIMD functions preserve some registers that normal functions
do not.  The default version of this function will do nothing.

Steve Ellcey
sell...@cavium.com


2018-11-08  Steve Ellcey  <sell...@cavium.com>

        * config/aarch64/aarch64.c (aarch64_simd_call_p): New function.
        (aarch64_remove_extra_call_preserved_regs): New function.
        (TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): New macro.
        * doc/tm.texi.in (TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS): New hook.
        * final.c (get_call_reg_set_usage): Call new hook.
        * target.def (remove_extra_call_preserved_regs): New hook.
        * targhooks.c (default_remove_extra_call_preserved_regs): New function.
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index c82c7b6..62112ac 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -1470,6 +1470,50 @@ aarch64_hard_regno_mode_ok (unsigned regno, machine_mode mode)
   return false;
 }
 
+/* Return true if the instruction is a call to a SIMD function, false
+   if it is not a SIMD function or if we do not know anything about
+   the function.  */
+
+static bool
+aarch64_simd_call_p (rtx_insn *insn)
+{
+  rtx symbol;
+  rtx call;
+  tree fndecl;
+
+  if (!insn)
+    return false;
+  call = get_call_rtx_from (insn);
+  if (!call)
+    return false;
+  symbol = XEXP (XEXP (call, 0), 0);
+  if (GET_CODE (symbol) != SYMBOL_REF)
+    return false;
+  fndecl = SYMBOL_REF_DECL (symbol);
+  if (!fndecl)
+    return false;
+
+  return aarch64_simd_decl_p (fndecl);
+}
+
+/* Possibly remove some registers from register set if we know they
+   are preserved by this call, even though they are marked as not
+   being callee saved in CALL_USED_REGISTERS.  */
+
+void
+aarch64_remove_extra_call_preserved_regs (rtx_insn *insn,
+					  HARD_REG_SET *return_set)
+{
+  int regno;
+
+  if (aarch64_simd_call_p (insn))
+    {
+      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+	if (FP_SIMD_SAVED_REGNUM_P (regno))
+	  CLEAR_HARD_REG_BIT (*return_set, regno);
+    }
+}
+
 /* Implement TARGET_HARD_REGNO_CALL_PART_CLOBBERED.  The callee only saves
    the lower 64 bits of a 128-bit register.  Tell the compiler the callee
    clobbers the top 64 bits when restoring the bottom 64 bits.  */
@@ -18290,6 +18334,10 @@ aarch64_libgcc_floating_mode_supported_p
 #undef TARGET_MODES_TIEABLE_P
 #define TARGET_MODES_TIEABLE_P aarch64_modes_tieable_p
 
+#undef TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS
+#define TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS \
+  aarch64_remove_extra_call_preserved_regs
+
 #undef TARGET_HARD_REGNO_CALL_PART_CLOBBERED
 #define TARGET_HARD_REGNO_CALL_PART_CLOBBERED \
   aarch64_hard_regno_call_part_clobbered
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index e8af1bf..73febe9 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -1704,6 +1704,8 @@ of @code{CALL_USED_REGISTERS}.
 @cindex call-saved register
 @hook TARGET_HARD_REGNO_CALL_PART_CLOBBERED
 
+@hook TARGET_REMOVE_EXTRA_CALL_PRESERVED_REGS
+
 @findex fixed_regs
 @findex call_used_regs
 @findex global_regs
diff --git a/gcc/final.c b/gcc/final.c
index 6e61f1e..8df869e 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -5080,7 +5080,7 @@ get_call_reg_set_usage (rtx_insn *insn, HARD_REG_SET *reg_set,
 	  return true;
 	}
     }
-
   COPY_HARD_REG_SET (*reg_set, default_set);
+  targetm.remove_extra_call_preserved_regs (insn, reg_set);
   return false;
 }
diff --git a/gcc/target.def b/gcc/target.def
index 4b166d1..25be927 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -5757,6 +5757,12 @@ for targets that don't have partly call-clobbered registers.",
  bool, (unsigned int regno, machine_mode mode),
  hook_bool_uint_mode_false)
 
+DEFHOOK
+(remove_extra_call_preserved_regs,
+ "This hook removes some registers from the callee used register set.",
+ void, (rtx_insn *insn, HARD_REG_SET *used_regs),
+ default_remove_extra_call_preserved_regs)
+
 /* Return the smallest number of different values for which it is best to
    use a jump-table instead of a tree of conditional branches.  */
 DEFHOOK
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 3d8b3b9..a9fb101 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -2372,4 +2372,11 @@ default_speculation_safe_value (machine_mode mode ATTRIBUTE_UNUSED,
   return result;
 }
 
+void
+default_remove_extra_call_preserved_regs (rtx_insn *insn ATTRIBUTE_UNUSED,
+					  HARD_REG_SET *used_regs
+						ATTRIBUTE_UNUSED)
+{
+}
+
 #include "gt-targhooks.h"

Reply via email to