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"