https://gcc.gnu.org/g:746bdda47afbbe4b7cf5581e1f6d86824fdc10b6
commit r17-2076-g746bdda47afbbe4b7cf5581e1f6d86824fdc10b6 Author: Kaz Kojima <[email protected]> Date: Fri Oct 18 11:09:37 2024 +0900 LRA: Add cannot_substitute_const_equiv_p target hook On SH fp constant load special instructions 'fldi0' and 'fldi1' are only valid for single-precision fp mode and thus depend on mode-switiching. LRA is not aware of that (or any mode-switching constraints) and would emit such constant loads in the wrong mode by changing fp-move related insn alternative without validating fp-mode attributes. This new target hook allows rejecting such potentially unsafe substitutions. This patch has been proposed here https://gcc.gnu.org/pipermail/gcc-patches/2026-March/709649.html but was initially rejected, as it's just papering over the real problem. Further discussion has clarified that this is a general issue in GCC, not only limited to LRA. Everything that runs after the mode-switching pass can make potentially unsafe insn transformations because nothing is validating the insn mode requirements against the current cpu/fpu mode state. After some reconsideration, this patch was approved https://gcc.gnu.org/pipermail/gcc-patches/2026-June/722024.html gcc/ChangeLog: PR target/117182 PR target/55212 * target.def (cannot_substitute_const_equiv_p): New target hook. * doc/tm.texi.in: Add it. * lra-constraints.cc (get_equiv): Use it. * config/sh/sh.cc (sh_cannot_substitute_const_equiv_p): Override it. * doc/tm.texi: Re-generate. Diff: --- gcc/config/sh/sh.cc | 21 +++++++++++++++++++++ gcc/doc/tm.texi | 17 ++++++++++++++--- gcc/doc/tm.texi.in | 2 ++ gcc/lra-constraints.cc | 6 +++++- gcc/target.def | 21 ++++++++++++++++++--- 5 files changed, 60 insertions(+), 7 deletions(-) diff --git a/gcc/config/sh/sh.cc b/gcc/config/sh/sh.cc index 1dbc63f177e2..4bf6ed41e067 100644 --- a/gcc/config/sh/sh.cc +++ b/gcc/config/sh/sh.cc @@ -271,6 +271,7 @@ static bool sh_legitimate_address_p (machine_mode, rtx, bool, static rtx sh_legitimize_address (rtx, rtx, machine_mode); static rtx sh_delegitimize_address (rtx); static bool sh_cannot_substitute_mem_equiv_p (rtx); +static bool sh_cannot_substitute_const_equiv_p (rtx); static bool sh_legitimize_address_displacement (rtx *, rtx *, poly_int64, machine_mode); static int scavenge_reg (HARD_REG_SET *s); @@ -610,6 +611,9 @@ TARGET_GNU_ATTRIBUTES (sh_attribute_table, #undef TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P #define TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P sh_cannot_substitute_mem_equiv_p +#undef TARGET_CANNOT_SUBSTITUTE_CONST_EQUIV_P +#define TARGET_CANNOT_SUBSTITUTE_CONST_EQUIV_P sh_cannot_substitute_const_equiv_p + #undef TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT #define TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT \ sh_legitimize_address_displacement @@ -11430,6 +11434,23 @@ sh_cannot_substitute_mem_equiv_p (rtx) return true; } +static bool +sh_cannot_substitute_const_equiv_p (rtx subst) +{ + /* If SUBST is SFmode const_double 0 or 1, the move insn may be + transformed into fldi0/1. This is potentially unsafe for fp mode + switching because fldi0/1 are single mode only instructions. + LRA could then insert an fldi0/1 while the fp mode = double is selected. + Currently there is no other way to check this or prevent this from + happening. See also PR 117182. */ + + if (GET_MODE (subst) == SFmode + && (real_equal (CONST_DOUBLE_REAL_VALUE (subst), &dconst1) + || real_equal (CONST_DOUBLE_REAL_VALUE (subst), &dconst0))) + return true; + return false; +} + /* Implement TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT. */ static bool sh_legitimize_address_displacement (rtx *offset1, rtx *offset2, diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index d62f29324737..6178db74d2fc 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -3122,9 +3122,20 @@ A target hook which returns @code{true} if @var{subst} can't substitute safely pseudos with equivalent memory values during register allocation. The default version of this target hook returns @code{false}. -On most machines, this default should be used. For generally -machines with non orthogonal register usage for addressing, such -as SH, this hook can be used to avoid excessive spilling. +On most machines, this default should be used. For machines with +non-orthogonal register usage for addressing, such as SH, +this hook can be used to avoid excessive spilling. +@end deftypefn + +@deftypefn {Target Hook} bool TARGET_CANNOT_SUBSTITUTE_CONST_EQUIV_P (rtx @var{subst}) +A target hook which returns @code{true} if @var{subst} can't +substitute safely pseudos with equivalent constant values during +register allocation. +The default version of this target hook returns @code{false}. +On most machines, this default should be used. For machines with +special constant load instructions that have additional constraints +or being dependent on mode-switching, such as SH, this hook can be +used to avoid unsafe substitution. @end deftypefn @deftypefn {Target Hook} bool TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT (rtx *@var{offset1}, rtx *@var{offset2}, poly_int64 @var{orig_offset}, machine_mode @var{mode}) diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 2aa58133d660..0a97b0fa2e44 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -2436,6 +2436,8 @@ in the reload pass. @hook TARGET_CANNOT_SUBSTITUTE_MEM_EQUIV_P +@hook TARGET_CANNOT_SUBSTITUTE_CONST_EQUIV_P + @hook TARGET_LEGITIMIZE_ADDRESS_DISPLACEMENT @hook TARGET_SPILL_CLASS diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc index aed3b77038d4..128857f86f61 100644 --- a/gcc/lra-constraints.cc +++ b/gcc/lra-constraints.cc @@ -581,7 +581,11 @@ get_equiv (rtx x) return res; } if ((res = ira_reg_equiv[regno].constant) != NULL_RTX) - return res; + { + if (targetm.cannot_substitute_const_equiv_p (res)) + return x; + return res; + } if ((res = ira_reg_equiv[regno].invariant) != NULL_RTX) return res; gcc_unreachable (); diff --git a/gcc/target.def b/gcc/target.def index 7881a2fa33a9..884fe1bd57e1 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -6239,9 +6239,24 @@ DEFHOOK substitute safely pseudos with equivalent memory values during\n\ register allocation.\n\ The default version of this target hook returns @code{false}.\n\ -On most machines, this default should be used. For generally\n\ -machines with non orthogonal register usage for addressing, such\n\ -as SH, this hook can be used to avoid excessive spilling.", +On most machines, this default should be used. For machines with\n\ +non-orthogonal register usage for addressing, such as SH,\n\ +this hook can be used to avoid excessive spilling.", + bool, (rtx subst), + hook_bool_rtx_false) + +/* This target hook allows the backend to avoid unsafe substitution + during register allocation. */ +DEFHOOK +(cannot_substitute_const_equiv_p, + "A target hook which returns @code{true} if @var{subst} can't\n\ +substitute safely pseudos with equivalent constant values during\n\ +register allocation.\n\ +The default version of this target hook returns @code{false}.\n\ +On most machines, this default should be used. For machines with\n\ +special constant load instructions that have additional constraints\n\ +or being dependent on mode-switching, such as SH, this hook can be\n\ +used to avoid unsafe substitution.", bool, (rtx subst), hook_bool_rtx_false)
