https://gcc.gnu.org/g:708cc223b0f8b96c804b86e97f414f4c1fe8c313

commit r17-5355-g708cc223b0f8b96c804b86e97f414f4c1fe8c313
Author: Takayuki 'January June' Suwa <[email protected]>
Date:   Mon Oct 19 17:08:07 2026 +0900

    xtensa: Tweak neg[sd]f2 MD patterns
    
    We have modified the negsf2 MD pattern several times, but unfortunately,
    a change introduced by another patch (efc69e28 "xtensa: Discourage use of
    hardware FP registers for SFmode load/store") is currently causing inter-
    ference, which has resulted in a performance regression.
    
    The key point is that under a TARGET_DENSITY configuration, when both the
    source and destination are address (GP) registers, using the NEG.[SD]
    machine instruction via a scratch hardware FP register increases the code
    size compared to derivation using only address registers (although # of
    instructions remains roughly the same).
    
    In practice, it is extremely difficult to resolve this issue by selecting
    alternative instructions based on operand constraints while also accounting
    for the influence of other factors.
    
    Therefore, we decided to implement the neg[sd]f2 pattern simply using only
    the floating-point machine instructions and address it with the peephole2
    pattern, which focuses only on the aforementioned key point.
    
    gcc/ChangeLog:
    
            * config/xtensa/xtensa.md (neg<mode>2):
            Change to define_insn pattern, without alternatives and split.
            (The two peephole2 patterns immediately following the above):
            New, for single and double precision, respectively.

Diff:
---
 gcc/config/xtensa/xtensa.md | 90 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 69 insertions(+), 21 deletions(-)

diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md
index 55920b0d5119..af71c929d0e7 100644
--- a/gcc/config/xtensa/xtensa.md
+++ b/gcc/config/xtensa/xtensa.md
@@ -757,32 +757,80 @@
   DONE;
 })
 
-(define_insn_and_split "neg<mode>2"
-  [(set (match_operand:SDF 0 "register_operand")
-        (neg:SDF (match_operand:SDF 1 "register_operand")))
-   (clobber (match_scratch:SI 2))]
+(define_insn "neg<mode>2"
+  [(set (match_operand:SDF 0 "register_operand" "=f")
+        (neg:SDF (match_operand:SDF 1 "register_operand" "f")))]
   "TARGET_FLOAT<sdf_mode_bits>"
-  {@ [cons: =0, 1, =2; attrs: type, length]
-     [D, D, &a; arith , 7] #
-     [f, f,  X; farith, 3] neg.<sd>\t%0, %1
-  }
-  "&& reload_completed && REG_P (operands[2])"
-  [(set (match_dup 2)
+  "neg.<sd>\t%0, %1"
+  [(set_attr "type"    "farith")
+   (set_attr "mode"    "<MODE>")
+   (set_attr "length"  "3")])
+
+(define_peephole2
+  [(set (match_operand:SF 0 "register_operand")
+       (match_operand:SF 1 "register_operand"))
+   (set (match_dup 0)
+       (neg:SF (match_dup 0)))
+   (set (match_operand:SF 2 "register_operand")
+       (match_dup 0))]
+  "TARGET_FLOAT32 && TARGET_DENSITY && optimize_size
+   && FP_REG_P (REGNO (operands[0]))
+   && GP_REG_P (REGNO (operands[1]))
+   && GP_REG_P (REGNO (operands[2]))"
+  [(set (match_dup 0)
        (const_int 1))
+   (set (match_dup 0)
+       (ashift:SI (match_dup 0)
+                  (const_int 31)))
    (set (match_dup 2)
-       (ashift:SI (match_dup 2)
+       (plus:SI (match_dup 1)
+                (match_dup 0)))]
+{
+  rtx scratch;
+  HARD_REG_SET regset;
+  CLEAR_HARD_REG_SET (regset);
+  scratch = peep2_find_free_register (0, 2, "a", SImode, &regset);
+  if (!scratch)
+    FAIL;
+  operands[0] = scratch;
+  operands[1] = gen_rtx_REG (SImode, REGNO (operands[1]));
+  operands[2] = gen_rtx_REG (SImode, REGNO (operands[2]));
+})
+
+(define_peephole2
+  [(set (match_operand:DF 0 "register_operand")
+       (match_operand:DF 1 "register_operand"))
+   (set (match_dup 0)
+       (neg:DF (match_dup 0)))
+   (set (match_operand:DF 2 "register_operand")
+       (match_dup 0))]
+  "TARGET_FLOAT64 && TARGET_DENSITY && optimize_size
+   && FP_REG_P (REGNO (operands[0]))
+   && GP_REG_P (REGNO (operands[1]))
+   && GP_REG_P (REGNO (operands[2]))"
+  [(set (match_dup 0)
+       (const_int 1))
+   (set (match_dup 0)
+       (ashift:SI (match_dup 0)
                   (const_int 31)))
-   (set (match_dup 3)
-       (plus:SI (match_dup 4)
-                (match_dup 2)))]
+   (set (match_dup 2)
+       (plus:SI (match_dup 1)
+                (match_dup 0)))]
 {
-  if (GET_MODE_SIZE (SImode) < GET_MODE_SIZE (<MODE>mode))
-    emit_insn (gen_movsi (gen_rtx_SUBREG (SImode, operands[0], 
subreg_lowpart_offset (SImode, <MODE>mode)),
-                         gen_rtx_SUBREG (SImode, operands[1], 
subreg_lowpart_offset (SImode, <MODE>mode))));
-  operands[3] = gen_rtx_SUBREG (SImode, operands[0], subreg_highpart_offset 
(SImode, <MODE>mode));
-  operands[4] = gen_rtx_SUBREG (SImode, operands[1], subreg_highpart_offset 
(SImode, <MODE>mode));
-}
-  [(set_attr "mode" "<MODE>")])
+  rtx scratch, lo_src, lo_dest;
+  HARD_REG_SET regset;
+  CLEAR_HARD_REG_SET (regset);
+  scratch = peep2_find_free_register (0, 2, "a", SImode, &regset);
+  if (!scratch)
+    FAIL;
+  lo_src = gen_lowpart (SImode, operands[1]);
+  lo_dest = gen_lowpart (SImode, operands[2]);
+  if (! rtx_equal_p (lo_dest, lo_src))
+    emit_insn (gen_movsi (lo_dest, lo_src));
+  operands[0] = scratch;
+  operands[1] = gen_highpart (SImode, operands[1]);
+  operands[2] = gen_highpart (SImode, operands[2]);
+})
 
 
 ;; Logical instructions.

Reply via email to