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.
This commit is contained in:
Takayuki 'January June' Suwa 2025-10-08 10:27:48 +09:00 committed by Max Filippov
parent 4864f24c86
commit b6af5f46e3
3 changed files with 113 additions and 55 deletions

View File

@ -59,7 +59,6 @@ extern char *xtensa_emit_sibcall (int, rtx *);
extern bool xtensa_tls_referenced_p (rtx); extern bool xtensa_tls_referenced_p (rtx);
extern enum rtx_code xtensa_shlrd_which_direction (rtx, rtx); extern enum rtx_code xtensa_shlrd_which_direction (rtx, rtx);
extern bool xtensa_postreload_completed_p (void); extern bool xtensa_postreload_completed_p (void);
extern void xtensa_split_DI_reg_imm (rtx *);
extern char *xtensa_bswapsi2_output (rtx_insn *, const char *); extern char *xtensa_bswapsi2_output (rtx_insn *, const char *);
#ifdef TREE_CODE #ifdef TREE_CODE

View File

@ -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. /* Return the asm output string of bswapsi2_internal insn pattern.
It does this by scanning backwards for the BB from the specified insn, 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 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; 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 /* Replace the source of [SH]Imode allocation whose value does not fit
into signed 12 bits with a reference to litpool entry. */ into signed 12 bits with a reference to litpool entry. */
@ -5956,6 +6031,11 @@ do_largeconst (void)
bool optimize_enabled = optimize && !optimize_debug; bool optimize_enabled = optimize && !optimize_debug;
rtx_insn *insn; 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)) for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (NONJUMP_INSN_P (insn)) if (NONJUMP_INSN_P (insn))
{ {
@ -5970,6 +6050,12 @@ do_largeconst (void)
fit into signed 12 bits with a reference to litpool entry. */ fit into signed 12 bits with a reference to litpool entry. */
if (replacing_required) if (replacing_required)
litpool_set_src (insn); 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);
} }
} }

View File

@ -1219,22 +1219,8 @@
(match_operand:DI 1 "general_operand" ""))] (match_operand:DI 1 "general_operand" ""))]
"" ""
{ {
if (CONSTANT_P (operands[1])) if (!TARGET_CONST16 && CONSTANT_P (operands[1]))
{ operands[1] = force_const_mem (DImode, 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 (!register_operand (operands[0], DImode) if (!register_operand (operands[0], DImode)
&& !register_operand (operands[1], DImode)) && !register_operand (operands[1], DImode))
@ -1244,8 +1230,8 @@
}) })
(define_insn_and_split "movdi_internal" (define_insn_and_split "movdi_internal"
[(set (match_operand:DI 0 "nonimmed_operand" "=a,W,a,a,U") [(set (match_operand:DI 0 "nonimmed_operand" "=a,a,W,a,a,U")
(match_operand:DI 1 "move_operand" "r,i,T,U,r"))] (match_operand:DI 1 "move_operand" "r,Y,i,T,U,r"))]
"register_operand (operands[0], DImode) "register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode)" || register_operand (operands[1], DImode)"
"#" "#"
@ -1260,22 +1246,9 @@
std::swap (operands[2], operands[3]); 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 "mode" "DI")
(set_attr "length" "6,12,6,6,6")]) (set_attr "length" "6,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);
})
;; 32-bit Integer moves ;; 32-bit Integer moves