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)

Reply via email to