https://gcc.gnu.org/g:b6af5f46e35d0201dd43d0d7fd5c1fbcbf2177eb
commit r16-4323-gb6af5f46e35d0201dd43d0d7fd5c1fbcbf2177eb Author: Takayuki 'January June' Suwa <[email protected]> Date: Wed Oct 8 10:27:48 2025 +0900 xtensa: Change the splitting of D[IF]mode constant assignments to be implemented in xt_largeconst instead of define_split This patch moves the process of splitting D[IF]mode constant assignments into SImode ones from the define_split implementation after reloading to processing within the "xt_largeconst" target-specific pass. It also converts SFmode constant assignments into bit-equivalent SImode ones. This allows these assignments to be processed by the "constantsynth" optimization, which will be reimplemented later. gcc/ChangeLog: * config/xtensa/xtensa-protos.h (xtensa_split_DI_reg_imm): Remove. * config/xtensa/xtensa.cc (xtensa_split_DI_reg_imm): Remove. (split_DI_SF_DF_const): New worker function. (do_largeconst): Add a call to split_DI_SF_DF_const() to the insn enumeration loop. * config/xtensa/xtensa.md (movdi): Remove split code when the source is constant. (movdi_internal): Add a new constraint pair (a, Y) to the second of the existing constraint alternatives. (The auxiliary define_split for movdi_internal): Remove. Diff: --- gcc/config/xtensa/xtensa-protos.h | 1 - gcc/config/xtensa/xtensa.cc | 128 +++++++++++++++++++++++++++++++------- gcc/config/xtensa/xtensa.md | 39 ++---------- 3 files changed, 113 insertions(+), 55 deletions(-) diff --git a/gcc/config/xtensa/xtensa-protos.h b/gcc/config/xtensa/xtensa-protos.h index c538e483cfc6..562e4b9283b3 100644 --- a/gcc/config/xtensa/xtensa-protos.h +++ b/gcc/config/xtensa/xtensa-protos.h @@ -59,7 +59,6 @@ extern char *xtensa_emit_sibcall (int, rtx *); extern bool xtensa_tls_referenced_p (rtx); extern enum rtx_code xtensa_shlrd_which_direction (rtx, rtx); extern bool xtensa_postreload_completed_p (void); -extern void xtensa_split_DI_reg_imm (rtx *); extern char *xtensa_bswapsi2_output (rtx_insn *, const char *); #ifdef TREE_CODE diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc index c878f1183c6b..110639f2218a 100644 --- a/gcc/config/xtensa/xtensa.cc +++ b/gcc/config/xtensa/xtensa.cc @@ -2633,27 +2633,6 @@ xtensa_postreload_completed_p (void) } -/* Split a DImode pair of reg (operand[0]) and const_int (operand[1]) into - two SImode pairs, the low-part (operands[0] and [1]) and the high-part - (operands[2] and [3]). */ - -void -xtensa_split_DI_reg_imm (rtx *operands) -{ - rtx lowpart, highpart; - - if (WORDS_BIG_ENDIAN) - split_double (operands[1], &highpart, &lowpart); - else - split_double (operands[1], &lowpart, &highpart); - - operands[3] = highpart; - operands[2] = gen_highpart (SImode, operands[0]); - operands[1] = lowpart; - operands[0] = gen_lowpart (SImode, operands[0]); -} - - /* Return the asm output string of bswapsi2_internal insn pattern. It does this by scanning backwards for the BB from the specified insn, and if an another bswapsi2_internal is found, it omits the instruction @@ -5892,6 +5871,102 @@ FPreg_neg_scaled_simm12b (rtx_insn *insn) return false; } +/* Split DI/SF/DFmode constant assignments into pairs of SImode ones. This + is also the pre-processing for constantsynth optimization that follows + immediately after. + + Note that all constant values and assignments are treated as SImode + because: + + - Synthesis methods rely on SImode operations + - SImode assignments may be shorter + - More opportunity for sharing literal pool entries + + This behavior would be acceptable if TARGET_CAN_CHANGE_MODE_CLASS always + returned true (the current and default configuration). */ + +static bool +split_DI_SF_DF_const (rtx_insn *insn) +{ + rtx pat, dest, src, dest0, dest1, src0, src1, src0c, src1c; + int regno; + + if (GET_CODE (pat = PATTERN (insn)) != SET + || ! REG_P (dest = SET_DEST (pat)) || ! GP_REG_P (regno = REGNO (dest))) + return false; + + /* It is more efficient to assign SFmode literal constants using their + bit-equivalent SImode ones, thus we convert them so. */ + src = avoid_constant_pool_reference (SET_SRC (pat)); + if (GET_MODE (dest) == SFmode + && CONST_DOUBLE_P (src) && GET_MODE (src) == SFmode) + { + long l; + REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (src), l); + src0 = GEN_INT ((int32_t)l), dest0 = gen_rtx_REG (SImode, regno); + if (dump_file) + { + fputs ("split_DI_SF_DF_const: ", dump_file); + dump_value_slim (dump_file, src, 0); + fprintf (dump_file, + "f -> " HOST_WIDE_INT_PRINT_DEC " (" + HOST_WIDE_INT_PRINT_HEX ")\n", + INTVAL (src0), INTVAL (src0)); + } + src0c = NULL_RTX; + if (!TARGET_CONST16 && !TARGET_AUTO_LITPOOLS + && ! xtensa_simm12b (INTVAL (src0))) + src0c = src0, src0 = force_const_mem (SImode, src0); + remove_reg_equal_equiv_notes (insn); + validate_change (insn, &PATTERN (insn), gen_rtx_SET (dest0, src0), 0); + if (src0c) + add_reg_note (insn, REG_EQUIV, copy_rtx (src0c)); + return true; + } + + /* Splitting a D[IF]mode literal constant into two with split_double() + results in a pair of CONST_INTs, so they are assigned in SImode + regardless of the original source mode. */ + if ((GET_MODE (dest) == DImode && CONST_INT_P (src)) + || (GET_MODE (dest) == DFmode + && CONST_DOUBLE_P (src) && GET_MODE (src) == DFmode)) + { + dest0 = gen_rtx_REG (SImode, regno); + dest1 = gen_rtx_REG (SImode, regno + 1); + split_double (src, &src0, &src1); + if (dump_file) + { + fputs ("split_DI_SF_DF_const: ", dump_file); + dump_value_slim (dump_file, src, 0); + fprintf (dump_file, + " -> " HOST_WIDE_INT_PRINT_DEC " (" + HOST_WIDE_INT_PRINT_HEX "), " + HOST_WIDE_INT_PRINT_DEC " (" + HOST_WIDE_INT_PRINT_HEX ")\n", + INTVAL (src0), INTVAL (src0), + INTVAL (src1), INTVAL (src1)); + } + src1c = src0c = NULL_RTX; + if (!TARGET_CONST16 && !TARGET_AUTO_LITPOOLS) + { + if (! xtensa_simm12b (INTVAL (src0))) + src0c = src0, src0 = force_const_mem (SImode, src0); + if (! xtensa_simm12b (INTVAL (src1))) + src1c = src1, src1 = force_const_mem (SImode, src1); + } + remove_reg_equal_equiv_notes (insn); + validate_change (insn, &PATTERN (insn), gen_rtx_SET (dest0, src0), 0); + if (src0c) + add_reg_note (insn, REG_EQUIV, copy_rtx (src0c)); + insn = emit_insn_after (gen_rtx_SET (dest1, src1), insn); + if (src1c) + add_reg_note (insn, REG_EQUIV, copy_rtx (src1c)); + return true; + } + + return false; +} + /* Replace the source of [SH]Imode allocation whose value does not fit into signed 12 bits with a reference to litpool entry. */ @@ -5956,6 +6031,11 @@ do_largeconst (void) bool optimize_enabled = optimize && !optimize_debug; rtx_insn *insn; + /* Verify the legitimacy of replacing constant assignments in + DI/SF/DFmode with those in SImode. */ + gcc_assert (targetm.can_change_mode_class + == hook_bool_mode_mode_reg_class_t_true); + for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) if (NONJUMP_INSN_P (insn)) { @@ -5970,6 +6050,12 @@ do_largeconst (void) fit into signed 12 bits with a reference to litpool entry. */ if (replacing_required) litpool_set_src (insn); + + /* Split DI/SF/DFmode constant assignments into pairs of SImode + ones. This is also the pre-processing for constantsynth opti- + mization that follows immediately after. */ + if (replacing_required) + split_DI_SF_DF_const (insn); } } diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md index 9a0c631dc3f4..a5c8a66aafb2 100644 --- a/gcc/config/xtensa/xtensa.md +++ b/gcc/config/xtensa/xtensa.md @@ -1219,22 +1219,8 @@ (match_operand:DI 1 "general_operand" ""))] "" { - if (CONSTANT_P (operands[1])) - { - /* Split in halves if 64-bit Const-to-Reg moves - because of offering further optimization opportunities. */ - if (register_operand (operands[0], DImode)) - { - rtx ops[4] = { operands[0], operands[1] }; - xtensa_split_DI_reg_imm (ops); - emit_move_insn (ops[0], ops[1]); - emit_move_insn (ops[2], ops[3]); - DONE; - } - - if (!TARGET_CONST16) - operands[1] = force_const_mem (DImode, operands[1]); - } + if (!TARGET_CONST16 && CONSTANT_P (operands[1])) + operands[1] = force_const_mem (DImode, operands[1]); if (!register_operand (operands[0], DImode) && !register_operand (operands[1], DImode)) @@ -1244,8 +1230,8 @@ }) (define_insn_and_split "movdi_internal" - [(set (match_operand:DI 0 "nonimmed_operand" "=a,W,a,a,U") - (match_operand:DI 1 "move_operand" "r,i,T,U,r"))] + [(set (match_operand:DI 0 "nonimmed_operand" "=a,a,W,a,a,U") + (match_operand:DI 1 "move_operand" "r,Y,i,T,U,r"))] "register_operand (operands[0], DImode) || register_operand (operands[1], DImode)" "#" @@ -1260,22 +1246,9 @@ std::swap (operands[2], operands[3]); } } - [(set_attr "type" "move,move,load,load,store") + [(set_attr "type" "move,load,move,load,load,store") (set_attr "mode" "DI") - (set_attr "length" "6,12,6,6,6")]) - -(define_split - [(set (match_operand:DI 0 "register_operand") - (match_operand:DI 1 "const_int_operand"))] - "!TARGET_CONST16 - && ! xtensa_postreload_completed_p ()" - [(set (match_dup 0) - (match_dup 1)) - (set (match_dup 2) - (match_dup 3))] -{ - xtensa_split_DI_reg_imm (operands); -}) + (set_attr "length" "6,6,12,6,6,6")]) ;; 32-bit Integer moves
