return align;
}
-/* Return the widest QI vector, if QI_MODE is true, or integer mode
- that is narrower than SIZE bytes. */
+/* Return true if we know how to implement OP using vectors of bytes. */
+static bool
+can_use_qi_vectors (by_pieces_operation op)
+{
+ return (op == COMPARE_BY_PIECES
+ || op == SET_BY_PIECES
+ || op == CLEAR_BY_PIECES);
+}
+
+/* Return true if optabs exists for the mode and certain by pieces
+ operations. */
+static bool
+qi_vector_mode_supported_p (fixed_size_mode mode, by_pieces_operation op)
+{
+ if ((op == SET_BY_PIECES || op == CLEAR_BY_PIECES)
+ && optab_handler (vec_duplicate_optab, mode) != CODE_FOR_nothing)
+ return true;
+
+ if (op == COMPARE_BY_PIECES
+ && optab_handler (mov_optab, mode) != CODE_FOR_nothing
+ && can_compare_p (EQ, mode, ccp_jump))
+ return true;
+ return false;
+}
+
+/* Return the widest mode that can be used to perform part of an
+ operation OP on SIZE bytes. Try to use QI vector modes where
+ possible. */
static fixed_size_mode
-widest_fixed_size_mode_for_size (unsigned int size, bool qi_vector)
+widest_fixed_size_mode_for_size (unsigned int size, by_pieces_operation op)
{
fixed_size_mode result = NARROWEST_INT_MODE;
gcc_checking_assert (size > 1);
/* Use QI vector only if size is wider than a WORD. */
- if (qi_vector && size > UNITS_PER_WORD)
+ if (can_use_qi_vectors (op) && size > UNITS_PER_WORD)
{
machine_mode mode;
fixed_size_mode candidate;
{
if (GET_MODE_SIZE (candidate) >= size)
break;
- if (optab_handler (vec_duplicate_optab, candidate)
- != CODE_FOR_nothing)
+ if (qi_vector_mode_supported_p (candidate, op))
result = candidate;
}
}
opt_scalar_int_mode tmode;
+ scalar_int_mode mode;
FOR_EACH_MODE_IN_CLASS (tmode, MODE_INT)
- if (GET_MODE_SIZE (tmode.require ()) < size)
- result = tmode.require ();
+ {
+ mode = tmode.require ();
+ if (GET_MODE_SIZE (mode) < size
+ && targetm.scalar_mode_supported_p (mode))
+ result = mode;
+ }
return result;
}
{
/* NB: Round up L and ALIGN to the widest integer mode for
MAX_SIZE. */
- mode = widest_fixed_size_mode_for_size (max_size,
- op == SET_BY_PIECES);
+ mode = widest_fixed_size_mode_for_size (max_size, op);
if (optab_handler (mov_optab, mode) != CODE_FOR_nothing)
{
unsigned HOST_WIDE_INT up = ROUND_UP (l, GET_MODE_SIZE (mode));
while (max_size > 1 && l > 0)
{
- mode = widest_fixed_size_mode_for_size (max_size,
- op == SET_BY_PIECES);
+ mode = widest_fixed_size_mode_for_size (max_size, op);
enum insn_code icode;
unsigned int modesize = GET_MODE_SIZE (mode);
bool m_push;
/* True if targetm.overlap_op_by_pieces_p () returns true. */
bool m_overlap_op_by_pieces;
- /* True if QI vector mode can be used. */
- bool m_qi_vector_mode;
+ /* The type of operation that we're performing. */
+ by_pieces_operation m_op;
/* Virtual functions, overriden by derived classes for the specific
operation. */
public:
op_by_pieces_d (unsigned int, rtx, bool, rtx, bool, by_pieces_constfn,
void *, unsigned HOST_WIDE_INT, unsigned int, bool,
- bool = false);
+ by_pieces_operation);
void run ();
};
void *from_cfn_data,
unsigned HOST_WIDE_INT len,
unsigned int align, bool push,
- bool qi_vector_mode)
+ by_pieces_operation op)
: m_to (to, to_load, NULL, NULL),
m_from (from, from_load, from_cfn, from_cfn_data),
m_len (len), m_max_size (max_pieces + 1),
- m_push (push), m_qi_vector_mode (qi_vector_mode)
+ m_push (push), m_op (op)
{
int toi = m_to.get_addr_inc ();
int fromi = m_from.get_addr_inc ();
{
/* Find the mode of the largest comparison. */
fixed_size_mode mode
- = widest_fixed_size_mode_for_size (m_max_size,
- m_qi_vector_mode);
+ = widest_fixed_size_mode_for_size (m_max_size, m_op);
m_from.decide_autoinc (mode, m_reverse, len);
m_to.decide_autoinc (mode, m_reverse, len);
if (len >= size && prepare_mode (mode, m_align))
break;
/* widest_fixed_size_mode_for_size checks SIZE > 1. */
- mode = widest_fixed_size_mode_for_size (size, m_qi_vector_mode);
+ mode = widest_fixed_size_mode_for_size (size, m_op);
}
while (1);
return mode;
op_by_pieces_d::smallest_fixed_size_mode_for_size (unsigned int size)
{
/* Use QI vector only for > size of WORD. */
- if (m_qi_vector_mode && size > UNITS_PER_WORD)
+ if (can_use_qi_vectors (m_op) && size > UNITS_PER_WORD)
{
machine_mode mode;
fixed_size_mode candidate;
break;
if (GET_MODE_SIZE (candidate) >= size
- && (optab_handler (vec_duplicate_optab, candidate)
- != CODE_FOR_nothing))
+ && qi_vector_mode_supported_p (candidate, m_op))
return candidate;
}
}
/* widest_fixed_size_mode_for_size checks M_MAX_SIZE > 1. */
fixed_size_mode mode
- = widest_fixed_size_mode_for_size (m_max_size, m_qi_vector_mode);
+ = widest_fixed_size_mode_for_size (m_max_size, m_op);
mode = get_usable_mode (mode, length);
by_pieces_prev to_prev = { nullptr, mode };
else
{
/* widest_fixed_size_mode_for_size checks SIZE > 1. */
- mode = widest_fixed_size_mode_for_size (size,
- m_qi_vector_mode);
+ mode = widest_fixed_size_mode_for_size (size, m_op);
mode = get_usable_mode (mode, length);
}
}
move_by_pieces_d (rtx to, rtx from, unsigned HOST_WIDE_INT len,
unsigned int align)
: op_by_pieces_d (MOVE_MAX_PIECES, to, false, from, true, NULL,
- NULL, len, align, PUSHG_P (to))
+ NULL, len, align, PUSHG_P (to), MOVE_BY_PIECES)
{
}
rtx finish_retmode (memop_ret);
class store_by_pieces_d : public op_by_pieces_d
{
insn_gen_fn m_gen_fun;
+
void generate (rtx, rtx, machine_mode) final override;
bool prepare_mode (machine_mode, unsigned int) final override;
public:
store_by_pieces_d (rtx to, by_pieces_constfn cfn, void *cfn_data,
unsigned HOST_WIDE_INT len, unsigned int align,
- bool qi_vector_mode)
+ by_pieces_operation op)
: op_by_pieces_d (STORE_MAX_PIECES, to, false, NULL_RTX, true, cfn,
- cfn_data, len, align, false, qi_vector_mode)
+ cfn_data, len, align, false, op)
{
}
rtx finish_retmode (memop_ret);
max_size = STORE_MAX_PIECES + 1;
while (max_size > 1 && l > 0)
{
- fixed_size_mode mode
- = widest_fixed_size_mode_for_size (max_size, memsetp);
+ auto op = memsetp ? SET_BY_PIECES : STORE_BY_PIECES;
+ auto mode = widest_fixed_size_mode_for_size (max_size, op);
icode = optab_handler (mov_optab, mode);
if (icode != CODE_FOR_nothing
optimize_insn_for_speed_p ()));
store_by_pieces_d data (to, constfun, constfundata, len, align,
- memsetp);
+ memsetp ? SET_BY_PIECES : STORE_BY_PIECES);
data.run ();
if (retmode != RETURN_BEGIN)
/* Use builtin_memset_read_str to support vector mode broadcast. */
char c = 0;
store_by_pieces_d data (to, builtin_memset_read_str, &c, len, align,
- true);
+ CLEAR_BY_PIECES);
data.run ();
}
void generate (rtx, rtx, machine_mode) final override;
bool prepare_mode (machine_mode, unsigned int) final override;
void finish_mode (machine_mode) final override;
+
public:
compare_by_pieces_d (rtx op0, rtx op1, by_pieces_constfn op1_cfn,
void *op1_cfn_data, HOST_WIDE_INT len, int align,
rtx_code_label *fail_label)
: op_by_pieces_d (COMPARE_MAX_PIECES, op0, true, op1, true, op1_cfn,
- op1_cfn_data, len, align, false)
+ op1_cfn_data, len, align, false, COMPARE_BY_PIECES)
{
m_fail_label = fail_label;
}