Hi,

In order to move the SH backend over to LRA there is one more missing piece.

On SH we have two fp constant load insns "fldi0" and "fldi1".  However, they
are bound to single-precision fp mode.  We were hitting some cases where LRA
wants to substitute constant loads, which have been emitted differently
originally, and picks up those "fldi0" / "fldi1" insns but doesn't check
whether they are valid for the current fp mode.

Eventually LRA should be taught to check that any substitution is valid for
any mode, not just fp mode.  But for now, the quick solution is to add a
cannot_substitute_const_equiv_p target hook.

Bootsrapped on x86_64.  OK to apply?

gcc/ChangeLog:
        PR target/117182
        * 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.
From 07255104e790cdeca62b01856d048692e46b77e2 Mon Sep 17 00:00:00 2001
From: Kaz Kojima <[email protected]>
Date: Fri, 18 Oct 2024 11:09:37 +0900
Subject: [PATCH] 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.  Since LRA is
not aware of that it would emit such constant loads in the wrong mode.  The new
target hook allows rejecting such potentially unsafe substitutions.

gcc/ChangeLog:
	PR target/117182
	* 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.
---
 gcc/config/sh/sh.cc    | 17 +++++++++++++++++
 gcc/doc/tm.texi        | 17 ++++++++++++++---
 gcc/doc/tm.texi.in     |  2 ++
 gcc/lra-constraints.cc |  6 +++++-
 gcc/target.def         | 21 ++++++++++++++++++---
 5 files changed, 56 insertions(+), 7 deletions(-)

diff --git a/gcc/config/sh/sh.cc b/gcc/config/sh/sh.cc
index d9b319c..e79b47d 100644
--- a/gcc/config/sh/sh.cc
+++ b/gcc/config/sh/sh.cc
@@ -270,8 +270,9 @@ static bool sh_legitimate_address_p (machine_mode, rtx, bool,
 				     code_helper = ERROR_MARK);
 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);
 
@@ -611,8 +612,11 @@ 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,8 +11434,21 @@ sh_cannot_substitute_mem_equiv_p (rtx)
      and end up memory save/restore insns which make the code worse.  */
   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 unsafe for fp mode switching
+     because fldi0/1 are single mode only instructions.  */
+  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,
 				    poly_int64 orig_offset,
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 394a46f..f5296fb 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -3120,11 +3120,22 @@ The default version of this target hook returns always false.
 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})
 This hook tries to split address offset @var{orig_offset} into
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 274bb89..19a47b7 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2425,8 +2425,10 @@ in the reload pass.
 @hook TARGET_DIFFERENT_ADDR_DISPLACEMENT_P
 
 @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 ccd68ef..5132e4a 100644
--- a/gcc/lra-constraints.cc
+++ b/gcc/lra-constraints.cc
@@ -579,9 +579,13 @@ get_equiv (rtx x)
 	return 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 206c94f..4411d4f 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6239,11 +6239,26 @@ DEFHOOK
  "A target hook which returns @code{true} if @var{subst} can't\n\
 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)
 
 /* This target hook allows the backend to legitimize base plus
--
libgit2 1.9.1

Reply via email to