mirror of git://gcc.gnu.org/git/gcc.git
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:
parent
4864f24c86
commit
b6af5f46e3
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue