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, ®set); + 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, ®set); + 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.
