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 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

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.
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);
}
}

View File

@ -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