return expand_binop (mode, binop, op0, op1, target, unsignedp, methods);
}
+/* Return whether OP0 and OP1 should be swapped when expanding a commutative
+ binop. Order them according to commutative_operand_precedence and, if
+ possible, try to put TARGET or a pseudo first. */
+static bool
+swap_commutative_operands_with_target (rtx target, rtx op0, rtx op1)
+{
+ int op0_prec = commutative_operand_precedence (op0);
+ int op1_prec = commutative_operand_precedence (op1);
+
+ if (op0_prec < op1_prec)
+ return true;
+
+ if (op0_prec > op1_prec)
+ return false;
+
+ /* With equal precedence, both orders are ok, but it is better if the
+ first operand is TARGET, or if both TARGET and OP0 are pseudos. */
+ if (target == 0 || REG_P (target))
+ return (REG_P (op1) && !REG_P (op0)) || target == op1;
+ else
+ return rtx_equal_p (op1, target);
+}
+
+
/* Generate code to perform an operation specified by BINOPTAB
on operands OP0 and OP1, with result having machine-mode MODE.
|| binoptab->code == ROTATERT);
rtx entry_last = get_last_insn ();
rtx last;
- bool first_pass_p;
+ bool first_pass_p = true;
class = GET_MODE_CLASS (mode);
{
commutative_op = 1;
- if (((target == 0 || REG_P (target))
- ? ((REG_P (op1)
- && !REG_P (op0))
- || target == op1)
- : rtx_equal_p (op1, target))
- || GET_CODE (op0) == CONST_INT)
+ if (swap_commutative_operands_with_target (target, op0, op1))
{
temp = op1;
op1 = op0;
/* If this is a multiply, see if we can do a widening operation that
takes operands of this mode and makes a wider mode. */
- if (binoptab == smul_optab && GET_MODE_WIDER_MODE (mode) != VOIDmode
+ if (binoptab == smul_optab
+ && GET_MODE_WIDER_MODE (mode) != VOIDmode
&& (((unsignedp ? umul_widen_optab : smul_widen_optab)
->handlers[(int) GET_MODE_WIDER_MODE (mode)].insn_code)
!= CODE_FOR_nothing))
can open-code the operation. Check for a widening multiply at the
wider mode as well. */
- if ((class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+ if (CLASS_HAS_WIDER_MODES_P (class)
&& methods != OPTAB_DIRECT && methods != OPTAB_LIB)
- for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
+ for (wider_mode = GET_MODE_WIDER_MODE (mode);
+ wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if (binoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing
/* Look for a wider mode of the same class for which it appears we can do
the operation. */
- if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+ if (CLASS_HAS_WIDER_MODES_P (class))
{
- for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
+ for (wider_mode = GET_MODE_WIDER_MODE (mode);
+ wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if ((binoptab->handlers[(int) wider_mode].insn_code
/* It can't be done in this mode. Can we do it in a wider mode? */
- if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+ if (CLASS_HAS_WIDER_MODES_P (class))
{
- for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
+ for (wider_mode = GET_MODE_WIDER_MODE (mode);
+ wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if (unoptab->handlers[(int) wider_mode].insn_code
/* It can't be done in this mode. Can we do it in a wider mode? */
- if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+ if (CLASS_HAS_WIDER_MODES_P (class))
{
- for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
+ for (wider_mode = GET_MODE_WIDER_MODE (mode);
+ wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if (binoptab->handlers[(int) wider_mode].insn_code
widen_clz (enum machine_mode mode, rtx op0, rtx target)
{
enum mode_class class = GET_MODE_CLASS (mode);
- if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+ if (CLASS_HAS_WIDER_MODES_P (class))
{
enum machine_mode wider_mode;
- for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
+ for (wider_mode = GET_MODE_WIDER_MODE (mode);
+ wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if (clz_optab->handlers[(int) wider_mode].insn_code
expand_parity (enum machine_mode mode, rtx op0, rtx target)
{
enum mode_class class = GET_MODE_CLASS (mode);
- if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+ if (CLASS_HAS_WIDER_MODES_P (class))
{
enum machine_mode wider_mode;
for (wider_mode = mode; wider_mode != VOIDmode;
goto try_libcall;
}
- if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
- for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
+ if (CLASS_HAS_WIDER_MODES_P (class))
+ for (wider_mode = GET_MODE_WIDER_MODE (mode);
+ wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if (unoptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing)
if (temp)
{
- if (class != MODE_INT)
+ if (class != MODE_INT
+ || !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+ GET_MODE_BITSIZE (wider_mode)))
{
if (target == 0)
target = gen_reg_rtx (mode);
if (unoptab->code == NEG)
{
/* Try negating floating point values by flipping the sign bit. */
- if (class == MODE_FLOAT)
+ if (SCALAR_FLOAT_MODE_P (mode))
{
temp = expand_absneg_bit (NEG, mode, op0, target);
if (temp)
/* It can't be done in this mode. Can we do it in a wider mode? */
- if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+ if (CLASS_HAS_WIDER_MODES_P (class))
{
- for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
+ for (wider_mode = GET_MODE_WIDER_MODE (mode);
+ wider_mode != VOIDmode;
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
{
if ((unoptab->handlers[(int) wider_mode].insn_code
return temp;
/* For floating point modes, try clearing the sign bit. */
- if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+ if (SCALAR_FLOAT_MODE_P (mode))
{
temp = expand_absneg_bit (ABS, mode, op0, target);
if (temp)
enum machine_mode mode = *pmode;
rtx x = *px, y = *py;
int unsignedp = *punsignedp;
- enum mode_class class;
-
- class = GET_MODE_CLASS (mode);
/* If we are inside an appropriately-short loop and we are optimizing,
force expensive constants into a register. */
/* Handle a lib call just for the mode we are using. */
- if (cmp_optab->handlers[(int) mode].libfunc && class != MODE_FLOAT)
+ if (cmp_optab->handlers[(int) mode].libfunc && !SCALAR_FLOAT_MODE_P (mode))
{
rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
rtx result;
return;
}
- gcc_assert (class == MODE_FLOAT);
+ gcc_assert (SCALAR_FLOAT_MODE_P (mode));
prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
}
return;
}
- if (class != MODE_INT && class != MODE_FLOAT
- && class != MODE_COMPLEX_FLOAT)
+ if (!CLASS_HAS_WIDER_MODES_P (class))
break;
wider_mode = GET_MODE_WIDER_MODE (wider_mode);
rtx libfunc = 0;
bool reversed_p = false;
- for (mode = orig_mode; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode))
+ for (mode = orig_mode;
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
{
if ((libfunc = code_to_optab[comparison]->handlers[mode].libfunc))
break;
enum insn_code icode;
rtx target = to;
enum machine_mode fmode, imode;
+ bool can_do_signed = false;
/* Crash now, because we won't be able to decide which mode to use. */
gcc_assert (GET_MODE (from) != VOIDmode);
continue;
icode = can_float_p (fmode, imode, unsignedp);
- if (icode == CODE_FOR_nothing && imode != GET_MODE (from) && unsignedp)
- icode = can_float_p (fmode, imode, 0), doing_unsigned = 0;
+ if (icode == CODE_FOR_nothing && unsignedp)
+ {
+ enum insn_code scode = can_float_p (fmode, imode, 0);
+ if (scode != CODE_FOR_nothing)
+ can_do_signed = true;
+ if (imode != GET_MODE (from))
+ icode = scode, doing_unsigned = 0;
+ }
if (icode != CODE_FOR_nothing)
{
/* Unsigned integer, and no way to convert directly.
Convert as signed, then conditionally adjust the result. */
- if (unsignedp)
+ if (unsignedp && can_do_signed)
{
rtx label = gen_label_rtx ();
rtx temp;
umul_highpart_optab = init_optab (UNKNOWN);
smul_widen_optab = init_optab (UNKNOWN);
umul_widen_optab = init_optab (UNKNOWN);
+ usmul_widen_optab = init_optab (UNKNOWN);
sdiv_optab = init_optab (DIV);
sdivv_optab = init_optabv (DIV);
sdivmod_optab = init_optab (UNKNOWN);
sync_lock_test_and_set[i] = CODE_FOR_nothing;
sync_lock_release[i] = CODE_FOR_nothing;
-#ifdef HAVE_SECONDARY_RELOADS
reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
-#endif
}
/* Fill in the optabs with the insns we support. */
/* Conversions. */
init_interclass_conv_libfuncs (sfloat_optab, "float",
MODE_INT, MODE_FLOAT);
+ init_interclass_conv_libfuncs (ufloat_optab, "floatun",
+ MODE_INT, MODE_FLOAT);
init_interclass_conv_libfuncs (sfix_optab, "fix",
MODE_FLOAT, MODE_INT);
init_interclass_conv_libfuncs (ufix_optab, "fixuns",
cc_op1 = XEXP (comparison, 1);
/* Expand both operands and force them in reg, if required. */
rtx_op1 = expand_expr (TREE_OPERAND (vec_cond_expr, 1),
- NULL_RTX, VOIDmode, 1);
+ NULL_RTX, VOIDmode, EXPAND_NORMAL);
if (!insn_data[icode].operand[1].predicate (rtx_op1, mode)
&& mode != VOIDmode)
rtx_op1 = force_reg (mode, rtx_op1);
rtx_op2 = expand_expr (TREE_OPERAND (vec_cond_expr, 2),
- NULL_RTX, VOIDmode, 1);
+ NULL_RTX, VOIDmode, EXPAND_NORMAL);
if (!insn_data[icode].operand[2].predicate (rtx_op2, mode)
&& mode != VOIDmode)
rtx_op2 = force_reg (mode, rtx_op2);