+2017-11-01 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * optabs-query.h (convert_optab_p): New function, split out from...
+ (convert_optab_handler): ...here.
+ (widening_optab_handler): Delete.
+ (find_widening_optab_handler): Remove permit_non_widening parameter.
+ (find_widening_optab_handler_and_mode): Likewise. Provide an
+ override that operates on mode class wrappers.
+ * optabs-query.c (widening_optab_handler): Delete.
+ (find_widening_optab_handler_and_mode): Remove permit_non_widening
+ parameter. Assert that the two modes are the same class and that
+ the "from" mode is narrower than the "to" mode. Use
+ convert_optab_handler instead of widening_optab_handler.
+ * expmed.c (expmed_mult_highpart_optab): Use convert_optab_handler
+ instead of widening_optab_handler.
+ * expr.c (expand_expr_real_2): Update calls to
+ find_widening_optab_handler.
+ * optabs.c (expand_widen_pattern_expr): Likewise.
+ (expand_binop_directly): Take the insn_code as a parameter.
+ (expand_binop): Only call find_widening_optab_handler for
+ conversion optabs; use optab_handler otherwise. Update calls
+ to find_widening_optab_handler and expand_binop_directly.
+ Use convert_optab_handler instead of widening_optab_handler.
+ * tree-ssa-math-opts.c (convert_mult_to_widen): Update calls to
+ find_widening_optab_handler and use scalar_mode rather than
+ machine_mode.
+ (convert_plusminus_to_widen): Likewise.
+
2017-11-01 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
/* Try widening multiplication. */
moptab = unsignedp ? umul_widen_optab : smul_widen_optab;
- if (widening_optab_handler (moptab, wider_mode, mode) != CODE_FOR_nothing
+ if (convert_optab_handler (moptab, wider_mode, mode) != CODE_FOR_nothing
&& mul_widen_cost (speed, wider_mode) < max_cost)
{
tem = expand_binop (wider_mode, moptab, op0, narrow_op1, 0,
/* Try widening multiplication of opposite signedness, and adjust. */
moptab = unsignedp ? smul_widen_optab : umul_widen_optab;
- if (widening_optab_handler (moptab, wider_mode, mode) != CODE_FOR_nothing
+ if (convert_optab_handler (moptab, wider_mode, mode) != CODE_FOR_nothing
&& size - 1 < BITS_PER_WORD
&& (mul_widen_cost (speed, wider_mode)
+ 2 * shift_cost (speed, mode, size-1)
{
machine_mode innermode = TYPE_MODE (TREE_TYPE (treeop0));
this_optab = usmul_widen_optab;
- if (find_widening_optab_handler (this_optab, mode, innermode, 0)
+ if (find_widening_optab_handler (this_optab, mode, innermode)
!= CODE_FOR_nothing)
{
if (TYPE_UNSIGNED (TREE_TYPE (treeop0)))
if (TREE_CODE (treeop0) != INTEGER_CST)
{
- if (find_widening_optab_handler (this_optab, mode, innermode, 0)
+ if (find_widening_optab_handler (this_optab, mode, innermode)
!= CODE_FOR_nothing)
{
expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
unsignedp, this_optab);
return REDUCE_BIT_FIELD (temp);
}
- if (find_widening_optab_handler (other_optab, mode, innermode, 0)
+ if (find_widening_optab_handler (other_optab, mode, innermode)
!= CODE_FOR_nothing
&& innermode == word_mode)
{
return true;
}
-/* Like optab_handler, but for widening_operations that have a
- TO_MODE and a FROM_MODE. */
-
-enum insn_code
-widening_optab_handler (optab op, machine_mode to_mode,
- machine_mode from_mode)
-{
- unsigned scode = (op << 16) | to_mode;
- if (to_mode != from_mode && from_mode != VOIDmode)
- {
- /* ??? Why does find_widening_optab_handler_and_mode attempt to
- widen things that can't be widened? E.g. add_optab... */
- if (op > LAST_CONV_OPTAB)
- return CODE_FOR_nothing;
- scode |= from_mode << 8;
- }
- return raw_optab_handler (scode);
-}
-
/* Find a widening optab even if it doesn't widen as much as we want.
E.g. if from_mode is HImode, and to_mode is DImode, and there is no
- direct HI->SI insn, then return SI->DI, if that exists.
- If PERMIT_NON_WIDENING is non-zero then this can be used with
- non-widening optabs also. */
+ direct HI->SI insn, then return SI->DI, if that exists. */
enum insn_code
find_widening_optab_handler_and_mode (optab op, machine_mode to_mode,
machine_mode from_mode,
- int permit_non_widening,
machine_mode *found_mode)
{
- for (; (permit_non_widening || from_mode != to_mode)
- && GET_MODE_SIZE (from_mode) <= GET_MODE_SIZE (to_mode)
- && from_mode != VOIDmode;
- from_mode = GET_MODE_WIDER_MODE (from_mode).else_void ())
+ gcc_checking_assert (GET_MODE_CLASS (from_mode) == GET_MODE_CLASS (to_mode));
+ gcc_checking_assert (from_mode < to_mode);
+ FOR_EACH_MODE (from_mode, from_mode, to_mode)
{
- enum insn_code handler = widening_optab_handler (op, to_mode,
- from_mode);
+ enum insn_code handler = convert_optab_handler (op, to_mode, from_mode);
if (handler != CODE_FOR_nothing)
{
#include "insn-opinit.h"
#include "target.h"
+/* Return true if OP is a conversion optab. */
+
+inline bool
+convert_optab_p (optab op)
+{
+ return op > unknown_optab && op <= LAST_CONV_OPTAB;
+}
+
/* Return the insn used to implement mode MODE of OP, or CODE_FOR_nothing
if the target does not have such an insn. */
machine_mode from_mode)
{
unsigned scode = (op << 16) | (from_mode << 8) | to_mode;
- gcc_assert (op > unknown_optab && op <= LAST_CONV_OPTAB);
+ gcc_assert (convert_optab_p (op));
return raw_optab_handler (scode);
}
enum insn_code can_fix_p (machine_mode, machine_mode, int, bool *);
bool can_conditionally_move_p (machine_mode mode);
bool can_vec_perm_p (machine_mode, bool, vec_perm_indices *);
-enum insn_code widening_optab_handler (optab, machine_mode, machine_mode);
/* Find a widening optab even if it doesn't widen as much as we want. */
-#define find_widening_optab_handler(A,B,C,D) \
- find_widening_optab_handler_and_mode (A, B, C, D, NULL)
+#define find_widening_optab_handler(A, B, C) \
+ find_widening_optab_handler_and_mode (A, B, C, NULL)
enum insn_code find_widening_optab_handler_and_mode (optab, machine_mode,
- machine_mode, int,
+ machine_mode,
machine_mode *);
int can_mult_highpart_p (machine_mode, bool);
bool can_vec_mask_load_store_p (machine_mode, machine_mode, bool);
bool can_atomic_load_p (machine_mode);
bool lshift_cheap_p (bool);
+/* Version of find_widening_optab_handler_and_mode that operates on
+ specific mode types. */
+
+template<typename T>
+inline enum insn_code
+find_widening_optab_handler_and_mode (optab op, const T &to_mode,
+ const T &from_mode, T *found_mode)
+{
+ machine_mode tmp;
+ enum insn_code icode = find_widening_optab_handler_and_mode
+ (op, machine_mode (to_mode), machine_mode (from_mode), &tmp);
+ if (icode != CODE_FOR_nothing && found_mode)
+ *found_mode = as_a <T> (tmp);
+ return icode;
+}
+
#endif
|| ops->code == WIDEN_MULT_MINUS_EXPR)
icode = find_widening_optab_handler (widen_pattern_optab,
TYPE_MODE (TREE_TYPE (ops->op2)),
- tmode0, 0);
+ tmode0);
else
icode = optab_handler (widen_pattern_optab, tmode0);
gcc_assert (icode != CODE_FOR_nothing);
}
/* Helper function for expand_binop: handle the case where there
- is an insn that directly implements the indicated operation.
+ is an insn ICODE that directly implements the indicated operation.
Returns null if this is not possible. */
static rtx
-expand_binop_directly (machine_mode mode, optab binoptab,
+expand_binop_directly (enum insn_code icode, machine_mode mode, optab binoptab,
rtx op0, rtx op1,
rtx target, int unsignedp, enum optab_methods methods,
rtx_insn *last)
{
- machine_mode from_mode = widened_mode (mode, op0, op1);
- enum insn_code icode = find_widening_optab_handler (binoptab, mode,
- from_mode, 1);
machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
machine_mode mode0, mode1, tmp_mode;
= (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN
? OPTAB_WIDEN : methods);
enum mode_class mclass;
+ enum insn_code icode;
machine_mode wider_mode;
scalar_int_mode int_mode;
rtx libfunc;
/* If we can do it with a three-operand insn, do so. */
- if (methods != OPTAB_MUST_WIDEN
- && find_widening_optab_handler (binoptab, mode,
- widened_mode (mode, op0, op1), 1)
- != CODE_FOR_nothing)
+ if (methods != OPTAB_MUST_WIDEN)
{
- temp = expand_binop_directly (mode, binoptab, op0, op1, target,
- unsignedp, methods, last);
- if (temp)
- return temp;
+ if (convert_optab_p (binoptab))
+ {
+ machine_mode from_mode = widened_mode (mode, op0, op1);
+ icode = find_widening_optab_handler (binoptab, mode, from_mode);
+ }
+ else
+ icode = optab_handler (binoptab, mode);
+ if (icode != CODE_FOR_nothing)
+ {
+ temp = expand_binop_directly (icode, mode, binoptab, op0, op1,
+ target, unsignedp, methods, last);
+ if (temp)
+ return temp;
+ }
}
/* If we were trying to rotate, and that didn't work, try rotating
the other direction before falling back to shifts and bitwise-or. */
if (((binoptab == rotl_optab
- && optab_handler (rotr_optab, mode) != CODE_FOR_nothing)
+ && (icode = optab_handler (rotr_optab, mode)) != CODE_FOR_nothing)
|| (binoptab == rotr_optab
- && optab_handler (rotl_optab, mode) != CODE_FOR_nothing))
+ && (icode = optab_handler (rotl_optab, mode)) != CODE_FOR_nothing))
&& is_int_mode (mode, &int_mode))
{
optab otheroptab = (binoptab == rotl_optab ? rotr_optab : rotl_optab);
gen_int_mode (bits, GET_MODE (op1)), op1,
NULL_RTX, unsignedp, OPTAB_DIRECT);
- temp = expand_binop_directly (int_mode, otheroptab, op0, newop1,
+ temp = expand_binop_directly (icode, int_mode, otheroptab, op0, newop1,
target, unsignedp, methods, last);
if (temp)
return temp;
else if (binoptab == rotr_optab)
otheroptab = vrotr_optab;
- if (otheroptab && optab_handler (otheroptab, mode) != CODE_FOR_nothing)
+ if (otheroptab
+ && (icode = optab_handler (otheroptab, mode)) != CODE_FOR_nothing)
{
/* The scalar may have been extended to be too wide. Truncate
it back to the proper size to fit in the broadcast vector. */
rtx vop1 = expand_vector_broadcast (mode, op1);
if (vop1)
{
- temp = expand_binop_directly (mode, otheroptab, op0, vop1,
+ temp = expand_binop_directly (icode, mode, otheroptab, op0, vop1,
target, unsignedp, methods, last);
if (temp)
return temp;
&& (find_widening_optab_handler ((unsignedp
? umul_widen_optab
: smul_widen_optab),
- next_mode, mode, 0)
+ next_mode, mode)
!= CODE_FOR_nothing)))
{
rtx xop0 = op0, xop1 = op1;
&& optab_handler (add_optab, word_mode) != CODE_FOR_nothing)
{
rtx product = NULL_RTX;
- if (widening_optab_handler (umul_widen_optab, int_mode, word_mode)
+ if (convert_optab_handler (umul_widen_optab, int_mode, word_mode)
!= CODE_FOR_nothing)
{
product = expand_doubleword_mult (int_mode, op0, op1, target,
}
if (product == NULL_RTX
- && (widening_optab_handler (smul_widen_optab, int_mode, word_mode)
+ && (convert_optab_handler (smul_widen_optab, int_mode, word_mode)
!= CODE_FOR_nothing))
{
product = expand_doubleword_mult (int_mode, op0, op1, target,
if (CLASS_HAS_WIDER_MODES_P (mclass))
{
+ /* This code doesn't make sense for conversion optabs, since we
+ wouldn't then want to extend the operands to be the same size
+ as the result. */
+ gcc_assert (!convert_optab_p (binoptab));
FOR_EACH_WIDER_MODE (wider_mode, mode)
{
- if (find_widening_optab_handler (binoptab, wider_mode, mode, 1)
- != CODE_FOR_nothing
+ if (optab_handler (binoptab, wider_mode)
|| (methods == OPTAB_LIB
&& optab_libfunc (binoptab, wider_mode)))
{
{
tree lhs, rhs1, rhs2, type, type1, type2;
enum insn_code handler;
- machine_mode to_mode, from_mode, actual_mode;
+ scalar_int_mode to_mode, from_mode, actual_mode;
optab op;
int actual_precision;
location_t loc = gimple_location (stmt);
op = usmul_widen_optab;
handler = find_widening_optab_handler_and_mode (op, to_mode, from_mode,
- 0, &actual_mode);
+ &actual_mode);
if (handler == CODE_FOR_nothing)
{
op = smul_widen_optab;
handler = find_widening_optab_handler_and_mode (op, to_mode,
- from_mode, 0,
+ from_mode,
&actual_mode);
if (handler == CODE_FOR_nothing)
optab this_optab;
enum tree_code wmult_code;
enum insn_code handler;
- scalar_mode to_mode, from_mode;
- machine_mode actual_mode;
+ scalar_mode to_mode, from_mode, actual_mode;
location_t loc = gimple_location (stmt);
int actual_precision;
bool from_unsigned1, from_unsigned2;
this transformation is likely to pessimize code. */
this_optab = optab_for_tree_code (wmult_code, optype, optab_default);
handler = find_widening_optab_handler_and_mode (this_optab, to_mode,
- from_mode, 0, &actual_mode);
+ from_mode, &actual_mode);
if (handler == CODE_FOR_nothing)
return false;