#define HWI_SIGN_EXTEND(low) \
((((HOST_WIDE_INT) low) < 0) ? ((HOST_WIDE_INT) -1) : ((HOST_WIDE_INT) 0))
+static rtx neg_const_int PARAMS ((enum machine_mode, rtx));
static int simplify_plus_minus_op_data_cmp PARAMS ((const void *,
const void *));
static rtx simplify_plus_minus PARAMS ((enum rtx_code,
static void simplify_binary_is2orm1 PARAMS ((PTR));
\f
+/* Negate a CONST_INT rtx, truncating (because a conversion from a
+ maximally negative number can overflow). */
+static rtx
+neg_const_int (mode, i)
+ enum machine_mode mode;
+ rtx i;
+{
+ return GEN_INT (trunc_int_for_mode (- INTVAL (i), mode));
+}
+
+\f
/* Make a binary operation by properly ordering the operands and
seeing if the expression folds. */
&& GET_MODE (op0) != VOIDmode
&& (code == PLUS || code == MINUS))
{
- HOST_WIDE_INT value = INTVAL (op1);
if (code == MINUS)
- value = -value;
- return plus_constant (op0, value);
+ op1 = neg_const_int (mode, op1);
+ return plus_constant (op0, INTVAL (op1));
}
else
return gen_rtx_fmt_ee (code, mode, op0, op1);
case SQRT:
case FLOAT_EXTEND:
case FLOAT_TRUNCATE:
+ case SS_TRUNCATE:
+ case US_TRUNCATE:
return 0;
default:
/* Don't let a relocatable value get a negative coeff. */
if (GET_CODE (op1) == CONST_INT && GET_MODE (op0) != VOIDmode)
- return plus_constant (op0, - INTVAL (op1));
+ return simplify_gen_binary (PLUS, mode,
+ op0,
+ neg_const_int (mode, op1));
/* (x - (x & y)) -> (x & ~y) */
if (GET_CODE (op1) == AND)
case DIV:
if (trueop1 == CONST1_RTX (mode))
- return op0;
+ {
+ /* On some platforms DIV uses narrower mode than its
+ operands. */
+ rtx x = gen_lowpart_common (mode, op0);
+ if (x)
+ return x;
+ else if (mode != GET_MODE (op0) && GET_MODE (op0) != VOIDmode)
+ return gen_lowpart_SUBREG (mode, op0);
+ else
+ return op0;
+ }
/* In IEEE floating point, 0/x is not always 0. */
if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
return op0;
break;
+ case SS_PLUS:
+ case US_PLUS:
+ case SS_MINUS:
+ case US_MINUS:
+ /* ??? There are simplifications that can be done. */
+ return 0;
+
default:
abort ();
}
if (n_ops != 7)
{
ops[n_ops].op = constm1_rtx;
- ops[n_ops].neg = this_neg;
+ ops[n_ops++].neg = this_neg;
ops[i].op = XEXP (this_op, 0);
ops[i].neg = !this_neg;
changed = 1;
case CONST_INT:
if (this_neg)
{
- ops[i].op = GEN_INT (- INTVAL (this_op));
+ ops[i].op = neg_const_int (mode, this_op);
ops[i].neg = 0;
changed = 1;
}
&& ! (GET_CODE (tem) == CONST
&& GET_CODE (XEXP (tem, 0)) == ncode
&& XEXP (XEXP (tem, 0), 0) == lhs
- && XEXP (XEXP (tem, 0), 1) == rhs))
+ && XEXP (XEXP (tem, 0), 1) == rhs)
+ /* Don't allow -x + -1 -> ~x simplifications in the
+ first pass. This allows us the chance to combine
+ the -1 with other constants. */
+ && ! (first
+ && GET_CODE (tem) == NOT
+ && XEXP (tem, 0) == rhs))
{
lneg &= rneg;
if (GET_CODE (tem) == NEG)
tem = XEXP (tem, 0), lneg = !lneg;
if (GET_CODE (tem) == CONST_INT && lneg)
- tem = GEN_INT (- INTVAL (tem)), lneg = 0;
+ tem = neg_const_int (mode, tem), lneg = 0;
ops[i].op = tem;
ops[i].neg = lneg;
&& GET_CODE (ops[n_ops - 1].op) == CONST_INT
&& CONSTANT_P (ops[n_ops - 2].op))
{
- HOST_WIDE_INT value = INTVAL (ops[n_ops - 1].op);
- if (ops[n_ops - 1].neg)
- value = -value;
- ops[n_ops - 2].op = plus_constant (ops[n_ops - 2].op, value);
+ rtx value = ops[n_ops - 1].op;
+ if (ops[n_ops - 1].neg ^ ops[n_ops - 2].neg)
+ value = neg_const_int (mode, value);
+ ops[n_ops - 2].op = plus_constant (ops[n_ops - 2].op, INTVAL (value));
n_ops--;
}
arguments are passed on 32-bit Sparc and should be fixed. */
if (HARD_REGNO_MODE_OK (final_regno, outermode)
|| ! HARD_REGNO_MODE_OK (REGNO (op), innermode))
- return gen_rtx_REG (outermode, final_regno);
+ {
+ rtx x = gen_rtx_REG (outermode, final_regno);
+
+ /* Propagate original regno. We don't have any way to specify
+ the offset inside orignal regno, so do so only for lowpart.
+ The information is used only by alias analysis that can not
+ grog partial register anyway. */
+
+ if (subreg_lowpart_offset (outermode, innermode) == byte)
+ ORIGINAL_REGNO (x) = ORIGINAL_REGNO (op);
+ return x;
+ }
}
/* If we have a SUBREG of a register that we are replacing and we are
res = simplify_subreg (outermode, part, GET_MODE (part), final_offset);
if (res)
return res;
- /* We can at least simplify it by referring directly to the relevent part. */
+ /* We can at least simplify it by referring directly to the relevant part. */
return gen_rtx_SUBREG (outermode, part, final_offset);
}