/* RTL simplification functions for GNU compiler.
- Copyright (C) 1987-2013 Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
#include "varasm.h"
#include "tm_p.h"
#include "regs.h"
#include "insn-config.h"
#include "recog.h"
#include "function.h"
+#include "insn-codes.h"
+#include "optabs.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
#include "expr.h"
#include "diagnostic-core.h"
-#include "ggc.h"
#include "target.h"
+#include "predict.h"
/* Simplification and canonicalization of RTL. */
#define HWI_SIGN_EXTEND(low) \
((((HOST_WIDE_INT) low) < 0) ? ((HOST_WIDE_INT) -1) : ((HOST_WIDE_INT) 0))
-static rtx neg_const_int (enum machine_mode, const_rtx);
+static rtx neg_const_int (machine_mode, const_rtx);
static bool plus_minus_operand_p (const_rtx);
-static bool simplify_plus_minus_op_data_cmp (rtx, rtx);
-static rtx simplify_plus_minus (enum rtx_code, enum machine_mode, rtx, rtx);
-static rtx simplify_immed_subreg (enum machine_mode, rtx, enum machine_mode,
+static rtx simplify_plus_minus (enum rtx_code, machine_mode, rtx, rtx);
+static rtx simplify_immed_subreg (machine_mode, rtx, machine_mode,
unsigned int);
-static rtx simplify_associative_operation (enum rtx_code, enum machine_mode,
+static rtx simplify_associative_operation (enum rtx_code, machine_mode,
rtx, rtx);
-static rtx simplify_relational_operation_1 (enum rtx_code, enum machine_mode,
- enum machine_mode, rtx, rtx);
-static rtx simplify_unary_operation_1 (enum rtx_code, enum machine_mode, rtx);
-static rtx simplify_binary_operation_1 (enum rtx_code, enum machine_mode,
+static rtx simplify_relational_operation_1 (enum rtx_code, machine_mode,
+ machine_mode, rtx, rtx);
+static rtx simplify_unary_operation_1 (enum rtx_code, machine_mode, rtx);
+static rtx simplify_binary_operation_1 (enum rtx_code, machine_mode,
rtx, rtx, rtx, rtx);
\f
/* Negate a CONST_INT rtx, truncating (because a conversion from a
maximally negative number can overflow). */
static rtx
-neg_const_int (enum machine_mode mode, const_rtx i)
+neg_const_int (machine_mode mode, const_rtx i)
{
return gen_int_mode (-(unsigned HOST_WIDE_INT) INTVAL (i), mode);
}
the most significant bit of machine mode MODE. */
bool
-mode_signbit_p (enum machine_mode mode, const_rtx x)
+mode_signbit_p (machine_mode mode, const_rtx x)
{
unsigned HOST_WIDE_INT val;
unsigned int width;
if (width <= HOST_BITS_PER_WIDE_INT
&& CONST_INT_P (x))
val = INTVAL (x);
+#if TARGET_SUPPORTS_WIDE_INT
+ else if (CONST_WIDE_INT_P (x))
+ {
+ unsigned int i;
+ unsigned int elts = CONST_WIDE_INT_NUNITS (x);
+ if (elts != (width + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT)
+ return false;
+ for (i = 0; i < elts - 1; i++)
+ if (CONST_WIDE_INT_ELT (x, i) != 0)
+ return false;
+ val = CONST_WIDE_INT_ELT (x, elts - 1);
+ width %= HOST_BITS_PER_WIDE_INT;
+ if (width == 0)
+ width = HOST_BITS_PER_WIDE_INT;
+ }
+#else
else if (width <= HOST_BITS_PER_DOUBLE_INT
&& CONST_DOUBLE_AS_INT_P (x)
&& CONST_DOUBLE_LOW (x) == 0)
val = CONST_DOUBLE_HIGH (x);
width -= HOST_BITS_PER_WIDE_INT;
}
+#endif
else
- /* FIXME: We don't yet have a representation for wider modes. */
+ /* X is not an integer constant. */
return false;
if (width < HOST_BITS_PER_WIDE_INT)
precision of MODE is too large to handle. */
bool
-val_signbit_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
+val_signbit_p (machine_mode mode, unsigned HOST_WIDE_INT val)
{
unsigned int width;
/* Test whether the most significant bit of mode MODE is set in VAL.
Returns false if the precision of MODE is too large to handle. */
bool
-val_signbit_known_set_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
+val_signbit_known_set_p (machine_mode mode, unsigned HOST_WIDE_INT val)
{
unsigned int width;
/* Test whether the most significant bit of mode MODE is clear in VAL.
Returns false if the precision of MODE is too large to handle. */
bool
-val_signbit_known_clear_p (enum machine_mode mode, unsigned HOST_WIDE_INT val)
+val_signbit_known_clear_p (machine_mode mode, unsigned HOST_WIDE_INT val)
{
unsigned int width;
seeing if the expression folds. */
rtx
-simplify_gen_binary (enum rtx_code code, enum machine_mode mode, rtx op0,
+simplify_gen_binary (enum rtx_code code, machine_mode mode, rtx op0,
rtx op1)
{
rtx tem;
/* Put complex operands first and constants second if commutative. */
if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
&& swap_commutative_operands_p (op0, op1))
- tem = op0, op0 = op1, op1 = tem;
+ std::swap (op0, op1);
return gen_rtx_fmt_ee (code, mode, op0, op1);
}
avoid_constant_pool_reference (rtx x)
{
rtx c, tmp, addr;
- enum machine_mode cmode;
+ machine_mode cmode;
HOST_WIDE_INT offset = 0;
switch (GET_CODE (x))
&& MEM_OFFSET_KNOWN_P (x))
{
tree decl = MEM_EXPR (x);
- enum machine_mode mode = GET_MODE (x);
+ machine_mode mode = GET_MODE (x);
HOST_WIDE_INT offset = 0;
switch (TREE_CODE (decl))
the specified operation. */
rtx
-simplify_gen_unary (enum rtx_code code, enum machine_mode mode, rtx op,
- enum machine_mode op_mode)
+simplify_gen_unary (enum rtx_code code, machine_mode mode, rtx op,
+ machine_mode op_mode)
{
rtx tem;
/* Likewise for ternary operations. */
rtx
-simplify_gen_ternary (enum rtx_code code, enum machine_mode mode,
- enum machine_mode op0_mode, rtx op0, rtx op1, rtx op2)
+simplify_gen_ternary (enum rtx_code code, machine_mode mode,
+ machine_mode op0_mode, rtx op0, rtx op1, rtx op2)
{
rtx tem;
CMP_MODE specifies mode comparison is done in. */
rtx
-simplify_gen_relational (enum rtx_code code, enum machine_mode mode,
- enum machine_mode cmp_mode, rtx op0, rtx op1)
+simplify_gen_relational (enum rtx_code code, machine_mode mode,
+ machine_mode cmp_mode, rtx op0, rtx op1)
{
rtx tem;
rtx (*fn) (rtx, const_rtx, void *), void *data)
{
enum rtx_code code = GET_CODE (x);
- enum machine_mode mode = GET_MODE (x);
- enum machine_mode op_mode;
+ machine_mode mode = GET_MODE (x);
+ machine_mode op_mode;
const char *fmt;
rtx op0, op1, op2, newx, op;
rtvec vec, newvec;
op0 = simplify_replace_fn_rtx (XEXP (x, 0), old_rtx, fn, data);
op1 = simplify_replace_fn_rtx (XEXP (x, 1), old_rtx, fn, data);
- /* (lo_sum (high x) x) -> x */
- if (GET_CODE (op0) == HIGH && rtx_equal_p (XEXP (op0, 0), op1))
- return op1;
+ /* (lo_sum (high x) y) -> y where x and y have the same base. */
+ if (GET_CODE (op0) == HIGH)
+ {
+ rtx base0, base1, offset0, offset1;
+ split_const (XEXP (op0, 0), &base0, &offset0);
+ split_const (op1, &base1, &offset1);
+ if (rtx_equal_p (base0, base1))
+ return op1;
+ }
if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
return x;
assume that truncating it too is a no-op. */
static rtx
-simplify_truncation (enum machine_mode mode, rtx op,
- enum machine_mode op_mode)
+simplify_truncation (machine_mode mode, rtx op,
+ machine_mode op_mode)
{
unsigned int precision = GET_MODE_UNIT_PRECISION (mode);
unsigned int op_precision = GET_MODE_UNIT_PRECISION (op_mode);
truncation without the extension. Finally, if the outermode
is larger than the origmode, we can just extend to the appropriate
mode. */
- enum machine_mode origmode = GET_MODE (XEXP (op, 0));
+ machine_mode origmode = GET_MODE (XEXP (op, 0));
if (mode == origmode)
return XEXP (op, 0);
else if (precision <= GET_MODE_UNIT_PRECISION (origmode))
XEXP (op, 0), origmode);
}
- /* Simplify (truncate:SI (op:DI (x:DI) (y:DI)))
- to (op:SI (truncate:SI (x:DI)) (truncate:SI (x:DI))). */
- if (GET_CODE (op) == PLUS
- || GET_CODE (op) == MINUS
- || GET_CODE (op) == MULT)
+ /* If the machine can perform operations in the truncated mode, distribute
+ the truncation, i.e. simplify (truncate:QI (op:SI (x:SI) (y:SI))) into
+ (op:QI (truncate:QI (x:SI)) (truncate:QI (y:SI))). */
+ if (1
+#ifdef WORD_REGISTER_OPERATIONS
+ && precision >= BITS_PER_WORD
+#endif
+ && (GET_CODE (op) == PLUS
+ || GET_CODE (op) == MINUS
+ || GET_CODE (op) == MULT))
{
rtx op0 = simplify_gen_unary (TRUNCATE, mode, XEXP (op, 0), op_mode);
if (op0)
MODE with input operand OP whose mode was originally OP_MODE.
Return zero if no simplification can be made. */
rtx
-simplify_unary_operation (enum rtx_code code, enum machine_mode mode,
- rtx op, enum machine_mode op_mode)
+simplify_unary_operation (enum rtx_code code, machine_mode mode,
+ rtx op, machine_mode op_mode)
{
rtx trueop, tem;
/* Perform some simplifications we can do even if the operands
aren't constant. */
static rtx
-simplify_unary_operation_1 (enum rtx_code code, enum machine_mode mode, rtx op)
+simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op)
{
enum rtx_code reversed;
rtx temp;
so we can perform the above simplification. */
if (STORE_FLAG_VALUE == -1
&& GET_CODE (op) == ASHIFTRT
- && GET_CODE (XEXP (op, 1))
+ && CONST_INT_P (XEXP (op, 1))
&& INTVAL (XEXP (op, 1)) == GET_MODE_PRECISION (mode) - 1)
return simplify_gen_relational (GE, mode, VOIDmode,
XEXP (op, 0), const0_rtx);
&& GET_CODE (SUBREG_REG (op)) == ASHIFT
&& XEXP (SUBREG_REG (op), 0) == const1_rtx)
{
- enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op));
+ machine_mode inner_mode = GET_MODE (SUBREG_REG (op));
rtx x;
x = gen_rtx_ROTATE (inner_mode,
if (GET_CODE (op) == IOR || GET_CODE (op) == AND)
{
rtx in1 = XEXP (op, 0), in2 = XEXP (op, 1);
- enum machine_mode op_mode;
+ machine_mode op_mode;
op_mode = GET_MODE (in1);
in1 = simplify_gen_unary (NOT, op_mode, in1, op_mode);
in2 = simplify_gen_unary (NOT, op_mode, in2, op_mode);
if (GET_CODE (in2) == NOT && GET_CODE (in1) != NOT)
- {
- rtx tem = in2;
- in2 = in1; in1 = tem;
- }
+ std::swap (in1, in2);
return gen_rtx_fmt_ee (GET_CODE (op) == IOR ? AND : IOR,
mode, in1, in2);
&& XEXP (op, 1) == const0_rtx
&& SCALAR_INT_MODE_P (GET_MODE (XEXP (op, 0))))
{
- enum machine_mode inner = GET_MODE (XEXP (op, 0));
+ machine_mode inner = GET_MODE (XEXP (op, 0));
int isize = GET_MODE_PRECISION (inner);
if (STORE_FLAG_VALUE == 1)
{
= (float_truncate:SF foo:DF).
(float_truncate:DF (float_extend:XF foo:SF))
- = (float_extend:SF foo:DF). */
+ = (float_extend:DF foo:SF). */
if ((GET_CODE (op) == FLOAT_TRUNCATE
&& flag_unsafe_math_optimizations)
|| GET_CODE (op) == FLOAT_EXTEND)
XEXP (op, 0), mode);
/* (float_truncate (float x)) is (float x) */
- if (GET_CODE (op) == FLOAT
+ if ((GET_CODE (op) == FLOAT || GET_CODE (op) == UNSIGNED_FLOAT)
&& (flag_unsafe_math_optimizations
|| (SCALAR_FLOAT_MODE_P (GET_MODE (op))
&& ((unsigned)significand_size (GET_MODE (op))
>= (GET_MODE_PRECISION (GET_MODE (XEXP (op, 0)))
- num_sign_bit_copies (XEXP (op, 0),
GET_MODE (XEXP (op, 0))))))))
- return simplify_gen_unary (FLOAT, mode,
+ return simplify_gen_unary (GET_CODE (op), mode,
XEXP (op, 0),
GET_MODE (XEXP (op, 0)));
rounding can't happen.
*/
if (GET_CODE (op) == FLOAT_EXTEND
- || (GET_CODE (op) == FLOAT
+ || ((GET_CODE (op) == FLOAT || GET_CODE (op) == UNSIGNED_FLOAT)
&& SCALAR_FLOAT_MODE_P (GET_MODE (op))
&& ((unsigned)significand_size (GET_MODE (op))
>= (GET_MODE_PRECISION (GET_MODE (XEXP (op, 0)))
&& (rcode == SIGN_EXTEND
|| (rcode == ASHIFTRT && CONST_INT_P (XEXP (rhs, 1)))))
{
- enum machine_mode lmode = GET_MODE (lhs);
- enum machine_mode rmode = GET_MODE (rhs);
+ machine_mode lmode = GET_MODE (lhs);
+ machine_mode rmode = GET_MODE (rhs);
int bits;
if (lcode == ASHIFTRT)
target mode is the same as the variable's promotion. */
if (GET_CODE (op) == SUBREG
&& SUBREG_PROMOTED_VAR_P (op)
- && ! SUBREG_PROMOTED_UNSIGNED_P (op)
+ && SUBREG_PROMOTED_SIGNED_P (op)
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
{
temp = rtl_hooks.gen_lowpart_no_emit (mode, op);
(sign_extend:M (zero_extend:N <X>)) is (zero_extend:M <X>). */
if (GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND)
{
- gcc_assert (GET_MODE_BITSIZE (mode)
- > GET_MODE_BITSIZE (GET_MODE (op)));
+ gcc_assert (GET_MODE_PRECISION (mode)
+ > GET_MODE_PRECISION (GET_MODE (op)));
return simplify_gen_unary (GET_CODE (op), mode, XEXP (op, 0),
GET_MODE (XEXP (op, 0)));
}
&& XEXP (XEXP (op, 0), 1) == XEXP (op, 1)
&& GET_MODE_BITSIZE (GET_MODE (op)) > INTVAL (XEXP (op, 1)))
{
- enum machine_mode tmode
+ machine_mode tmode
= mode_for_size (GET_MODE_BITSIZE (GET_MODE (op))
- INTVAL (XEXP (op, 1)), MODE_INT, 1);
gcc_assert (GET_MODE_BITSIZE (mode)
target mode is the same as the variable's promotion. */
if (GET_CODE (op) == SUBREG
&& SUBREG_PROMOTED_VAR_P (op)
- && SUBREG_PROMOTED_UNSIGNED_P (op) > 0
+ && SUBREG_PROMOTED_UNSIGNED_P (op)
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (XEXP (op, 0))))
{
temp = rtl_hooks.gen_lowpart_no_emit (mode, op);
&& (rcode == ZERO_EXTEND
|| (rcode == LSHIFTRT && CONST_INT_P (XEXP (rhs, 1)))))
{
- enum machine_mode lmode = GET_MODE (lhs);
- enum machine_mode rmode = GET_MODE (rhs);
+ machine_mode lmode = GET_MODE (lhs);
+ machine_mode rmode = GET_MODE (rhs);
int bits;
if (lcode == LSHIFTRT)
/* (zero_extend:M (lshiftrt:N (ashift <X> (const_int I)) (const_int I)))
is (zero_extend:M (subreg:O <X>)) if there is mode with
- GET_MODE_BITSIZE (N) - I bits. */
+ GET_MODE_PRECISION (N) - I bits. */
if (GET_CODE (op) == LSHIFTRT
&& GET_CODE (XEXP (op, 0)) == ASHIFT
&& CONST_INT_P (XEXP (op, 1))
&& XEXP (XEXP (op, 0), 1) == XEXP (op, 1)
- && GET_MODE_BITSIZE (GET_MODE (op)) > INTVAL (XEXP (op, 1)))
+ && GET_MODE_PRECISION (GET_MODE (op)) > INTVAL (XEXP (op, 1)))
{
- enum machine_mode tmode
- = mode_for_size (GET_MODE_BITSIZE (GET_MODE (op))
+ machine_mode tmode
+ = mode_for_size (GET_MODE_PRECISION (GET_MODE (op))
- INTVAL (XEXP (op, 1)), MODE_INT, 1);
if (tmode != BLKmode)
{
be MODE with input operand OP whose mode was originally OP_MODE.
Return zero if the value cannot be computed. */
rtx
-simplify_const_unary_operation (enum rtx_code code, enum machine_mode mode,
- rtx op, enum machine_mode op_mode)
+simplify_const_unary_operation (enum rtx_code code, machine_mode mode,
+ rtx op, machine_mode op_mode)
{
unsigned int width = GET_MODE_PRECISION (mode);
- unsigned int op_width = GET_MODE_PRECISION (op_mode);
if (code == VEC_DUPLICATE)
{
RTVEC_ELT (v, i) = op;
else
{
- enum machine_mode inmode = GET_MODE (op);
+ machine_mode inmode = GET_MODE (op);
int in_elt_size = GET_MODE_SIZE (GET_MODE_INNER (inmode));
unsigned in_n_elts = (GET_MODE_SIZE (inmode) / in_elt_size);
{
int elt_size = GET_MODE_SIZE (GET_MODE_INNER (mode));
unsigned n_elts = (GET_MODE_SIZE (mode) / elt_size);
- enum machine_mode opmode = GET_MODE (op);
+ machine_mode opmode = GET_MODE (op);
int op_elt_size = GET_MODE_SIZE (GET_MODE_INNER (opmode));
unsigned op_n_elts = (GET_MODE_SIZE (opmode) / op_elt_size);
rtvec v = rtvec_alloc (n_elts);
if (code == FLOAT && CONST_SCALAR_INT_P (op))
{
- HOST_WIDE_INT hv, lv;
REAL_VALUE_TYPE d;
- if (CONST_INT_P (op))
- lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
- else
- lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op);
+ if (op_mode == VOIDmode)
+ {
+ /* CONST_INT have VOIDmode as the mode. We assume that all
+ the bits of the constant are significant, though, this is
+ a dangerous assumption as many times CONST_INTs are
+ created and used with garbage in the bits outside of the
+ precision of the implied mode of the const_int. */
+ op_mode = MAX_MODE_INT;
+ }
- REAL_VALUE_FROM_INT (d, lv, hv, mode);
+ real_from_integer (&d, mode, std::make_pair (op, op_mode), SIGNED);
d = real_value_truncate (mode, d);
return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
}
else if (code == UNSIGNED_FLOAT && CONST_SCALAR_INT_P (op))
{
- HOST_WIDE_INT hv, lv;
REAL_VALUE_TYPE d;
- if (CONST_INT_P (op))
- lv = INTVAL (op), hv = HWI_SIGN_EXTEND (lv);
- else
- lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op);
-
- if (op_mode == VOIDmode
- || GET_MODE_PRECISION (op_mode) > HOST_BITS_PER_DOUBLE_INT)
- /* We should never get a negative number. */
- gcc_assert (hv >= 0);
- else if (GET_MODE_PRECISION (op_mode) <= HOST_BITS_PER_WIDE_INT)
- hv = 0, lv &= GET_MODE_MASK (op_mode);
+ if (op_mode == VOIDmode)
+ {
+ /* CONST_INT have VOIDmode as the mode. We assume that all
+ the bits of the constant are significant, though, this is
+ a dangerous assumption as many times CONST_INTs are
+ created and used with garbage in the bits outside of the
+ precision of the implied mode of the const_int. */
+ op_mode = MAX_MODE_INT;
+ }
- REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, mode);
+ real_from_integer (&d, mode, std::make_pair (op, op_mode), UNSIGNED);
d = real_value_truncate (mode, d);
return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
}
- if (CONST_INT_P (op)
- && width <= HOST_BITS_PER_WIDE_INT && width > 0)
+ if (CONST_SCALAR_INT_P (op) && width > 0)
{
- HOST_WIDE_INT arg0 = INTVAL (op);
- HOST_WIDE_INT val;
+ wide_int result;
+ machine_mode imode = op_mode == VOIDmode ? mode : op_mode;
+ rtx_mode_t op0 = std::make_pair (op, imode);
+ int int_value;
+
+#if TARGET_SUPPORTS_WIDE_INT == 0
+ /* This assert keeps the simplification from producing a result
+ that cannot be represented in a CONST_DOUBLE but a lot of
+ upstream callers expect that this function never fails to
+ simplify something and so you if you added this to the test
+ above the code would die later anyway. If this assert
+ happens, you just need to make the port support wide int. */
+ gcc_assert (width <= HOST_BITS_PER_DOUBLE_INT);
+#endif
switch (code)
{
case NOT:
- val = ~ arg0;
+ result = wi::bit_not (op0);
break;
case NEG:
- val = - arg0;
+ result = wi::neg (op0);
break;
case ABS:
- val = (arg0 >= 0 ? arg0 : - arg0);
+ result = wi::abs (op0);
break;
case FFS:
- arg0 &= GET_MODE_MASK (mode);
- val = ffs_hwi (arg0);
+ result = wi::shwi (wi::ffs (op0), mode);
break;
case CLZ:
- arg0 &= GET_MODE_MASK (mode);
- if (arg0 == 0 && CLZ_DEFINED_VALUE_AT_ZERO (mode, val))
- ;
- else
- val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 1;
+ if (wi::ne_p (op0, 0))
+ int_value = wi::clz (op0);
+ else if (! CLZ_DEFINED_VALUE_AT_ZERO (mode, int_value))
+ int_value = GET_MODE_PRECISION (mode);
+ result = wi::shwi (int_value, mode);
break;
case CLRSB:
- arg0 &= GET_MODE_MASK (mode);
- if (arg0 == 0)
- val = GET_MODE_PRECISION (mode) - 1;
- else if (arg0 >= 0)
- val = GET_MODE_PRECISION (mode) - floor_log2 (arg0) - 2;
- else if (arg0 < 0)
- val = GET_MODE_PRECISION (mode) - floor_log2 (~arg0) - 2;
+ result = wi::shwi (wi::clrsb (op0), mode);
break;
case CTZ:
- arg0 &= GET_MODE_MASK (mode);
- if (arg0 == 0)
- {
- /* Even if the value at zero is undefined, we have to come
- up with some replacement. Seems good enough. */
- if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, val))
- val = GET_MODE_PRECISION (mode);
- }
- else
- val = ctz_hwi (arg0);
+ if (wi::ne_p (op0, 0))
+ int_value = wi::ctz (op0);
+ else if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, int_value))
+ int_value = GET_MODE_PRECISION (mode);
+ result = wi::shwi (int_value, mode);
break;
case POPCOUNT:
- arg0 &= GET_MODE_MASK (mode);
- val = 0;
- while (arg0)
- val++, arg0 &= arg0 - 1;
+ result = wi::shwi (wi::popcount (op0), mode);
break;
case PARITY:
- arg0 &= GET_MODE_MASK (mode);
- val = 0;
- while (arg0)
- val++, arg0 &= arg0 - 1;
- val &= 1;
+ result = wi::shwi (wi::parity (op0), mode);
break;
case BSWAP:
- {
- unsigned int s;
-
- val = 0;
- for (s = 0; s < width; s += 8)
- {
- unsigned int d = width - s - 8;
- unsigned HOST_WIDE_INT byte;
- byte = (arg0 >> s) & 0xff;
- val |= byte << d;
- }
- }
+ result = wide_int (op0).bswap ();
break;
case TRUNCATE:
- val = arg0;
- break;
-
case ZERO_EXTEND:
- /* When zero-extending a CONST_INT, we need to know its
- original mode. */
- gcc_assert (op_mode != VOIDmode);
- if (op_width == HOST_BITS_PER_WIDE_INT)
- {
- /* If we were really extending the mode,
- we would have to distinguish between zero-extension
- and sign-extension. */
- gcc_assert (width == op_width);
- val = arg0;
- }
- else if (GET_MODE_BITSIZE (op_mode) < HOST_BITS_PER_WIDE_INT)
- val = arg0 & GET_MODE_MASK (op_mode);
- else
- return 0;
+ result = wide_int::from (op0, width, UNSIGNED);
break;
case SIGN_EXTEND:
- if (op_mode == VOIDmode)
- op_mode = mode;
- op_width = GET_MODE_PRECISION (op_mode);
- if (op_width == HOST_BITS_PER_WIDE_INT)
- {
- /* If we were really extending the mode,
- we would have to distinguish between zero-extension
- and sign-extension. */
- gcc_assert (width == op_width);
- val = arg0;
- }
- else if (op_width < HOST_BITS_PER_WIDE_INT)
- {
- val = arg0 & GET_MODE_MASK (op_mode);
- if (val_signbit_known_set_p (op_mode, val))
- val |= ~GET_MODE_MASK (op_mode);
- }
- else
- return 0;
+ result = wide_int::from (op0, width, SIGNED);
break;
case SQRT:
- case FLOAT_EXTEND:
- case FLOAT_TRUNCATE:
- case SS_TRUNCATE:
- case US_TRUNCATE:
- case SS_NEG:
- case US_NEG:
- case SS_ABS:
- return 0;
-
- default:
- gcc_unreachable ();
- }
-
- return gen_int_mode (val, mode);
- }
-
- /* We can do some operations on integer CONST_DOUBLEs. Also allow
- for a DImode operation on a CONST_INT. */
- else if (width <= HOST_BITS_PER_DOUBLE_INT
- && (CONST_DOUBLE_AS_INT_P (op) || CONST_INT_P (op)))
- {
- double_int first, value;
-
- if (CONST_DOUBLE_AS_INT_P (op))
- first = double_int::from_pair (CONST_DOUBLE_HIGH (op),
- CONST_DOUBLE_LOW (op));
- else
- first = double_int::from_shwi (INTVAL (op));
-
- switch (code)
- {
- case NOT:
- value = ~first;
- break;
-
- case NEG:
- value = -first;
- break;
-
- case ABS:
- if (first.is_negative ())
- value = -first;
- else
- value = first;
- break;
-
- case FFS:
- value.high = 0;
- if (first.low != 0)
- value.low = ffs_hwi (first.low);
- else if (first.high != 0)
- value.low = HOST_BITS_PER_WIDE_INT + ffs_hwi (first.high);
- else
- value.low = 0;
- break;
-
- case CLZ:
- value.high = 0;
- if (first.high != 0)
- value.low = GET_MODE_PRECISION (mode) - floor_log2 (first.high) - 1
- - HOST_BITS_PER_WIDE_INT;
- else if (first.low != 0)
- value.low = GET_MODE_PRECISION (mode) - floor_log2 (first.low) - 1;
- else if (! CLZ_DEFINED_VALUE_AT_ZERO (mode, value.low))
- value.low = GET_MODE_PRECISION (mode);
- break;
-
- case CTZ:
- value.high = 0;
- if (first.low != 0)
- value.low = ctz_hwi (first.low);
- else if (first.high != 0)
- value.low = HOST_BITS_PER_WIDE_INT + ctz_hwi (first.high);
- else if (! CTZ_DEFINED_VALUE_AT_ZERO (mode, value.low))
- value.low = GET_MODE_PRECISION (mode);
- break;
-
- case POPCOUNT:
- value = double_int_zero;
- while (first.low)
- {
- value.low++;
- first.low &= first.low - 1;
- }
- while (first.high)
- {
- value.low++;
- first.high &= first.high - 1;
- }
- break;
-
- case PARITY:
- value = double_int_zero;
- while (first.low)
- {
- value.low++;
- first.low &= first.low - 1;
- }
- while (first.high)
- {
- value.low++;
- first.high &= first.high - 1;
- }
- value.low &= 1;
- break;
-
- case BSWAP:
- {
- unsigned int s;
-
- value = double_int_zero;
- for (s = 0; s < width; s += 8)
- {
- unsigned int d = width - s - 8;
- unsigned HOST_WIDE_INT byte;
-
- if (s < HOST_BITS_PER_WIDE_INT)
- byte = (first.low >> s) & 0xff;
- else
- byte = (first.high >> (s - HOST_BITS_PER_WIDE_INT)) & 0xff;
-
- if (d < HOST_BITS_PER_WIDE_INT)
- value.low |= byte << d;
- else
- value.high |= byte << (d - HOST_BITS_PER_WIDE_INT);
- }
- }
- break;
-
- case TRUNCATE:
- /* This is just a change-of-mode, so do nothing. */
- value = first;
- break;
-
- case ZERO_EXTEND:
- gcc_assert (op_mode != VOIDmode);
-
- if (op_width > HOST_BITS_PER_WIDE_INT)
- return 0;
-
- value = double_int::from_uhwi (first.low & GET_MODE_MASK (op_mode));
- break;
-
- case SIGN_EXTEND:
- if (op_mode == VOIDmode
- || op_width > HOST_BITS_PER_WIDE_INT)
- return 0;
- else
- {
- value.low = first.low & GET_MODE_MASK (op_mode);
- if (val_signbit_known_set_p (op_mode, value.low))
- value.low |= ~GET_MODE_MASK (op_mode);
-
- value.high = HWI_SIGN_EXTEND (value.low);
- }
- break;
-
- case SQRT:
- return 0;
-
default:
return 0;
}
- return immed_double_int_const (value, mode);
+ return immed_wide_int_const (result, mode);
}
else if (CONST_DOUBLE_AS_FLOAT_P (op)
}
return CONST_DOUBLE_FROM_REAL_VALUE (d, mode);
}
-
else if (CONST_DOUBLE_AS_FLOAT_P (op)
&& SCALAR_FLOAT_MODE_P (GET_MODE (op))
&& GET_MODE_CLASS (mode) == MODE_INT
- && width <= HOST_BITS_PER_DOUBLE_INT && width > 0)
+ && width > 0)
{
/* Although the overflow semantics of RTL's FIX and UNSIGNED_FIX
operators are intentionally left unspecified (to ease implementation
/* This was formerly used only for non-IEEE float.
eggert@twinsun.com says it is safe for IEEE also. */
- HOST_WIDE_INT xh, xl, th, tl;
REAL_VALUE_TYPE x, t;
REAL_VALUE_FROM_CONST_DOUBLE (x, op);
+ wide_int wmax, wmin;
+ /* This is part of the abi to real_to_integer, but we check
+ things before making this call. */
+ bool fail;
+
switch (code)
{
case FIX:
return const0_rtx;
/* Test against the signed upper bound. */
- if (width > HOST_BITS_PER_WIDE_INT)
- {
- th = ((unsigned HOST_WIDE_INT) 1
- << (width - HOST_BITS_PER_WIDE_INT - 1)) - 1;
- tl = -1;
- }
- else
- {
- th = 0;
- tl = ((unsigned HOST_WIDE_INT) 1 << (width - 1)) - 1;
- }
- real_from_integer (&t, VOIDmode, tl, th, 0);
+ wmax = wi::max_value (width, SIGNED);
+ real_from_integer (&t, VOIDmode, wmax, SIGNED);
if (REAL_VALUES_LESS (t, x))
- {
- xh = th;
- xl = tl;
- break;
- }
+ return immed_wide_int_const (wmax, mode);
/* Test against the signed lower bound. */
- if (width > HOST_BITS_PER_WIDE_INT)
- {
- th = HOST_WIDE_INT_M1U << (width - HOST_BITS_PER_WIDE_INT - 1);
- tl = 0;
- }
- else
- {
- th = -1;
- tl = HOST_WIDE_INT_M1U << (width - 1);
- }
- real_from_integer (&t, VOIDmode, tl, th, 0);
+ wmin = wi::min_value (width, SIGNED);
+ real_from_integer (&t, VOIDmode, wmin, SIGNED);
if (REAL_VALUES_LESS (x, t))
- {
- xh = th;
- xl = tl;
- break;
- }
- REAL_VALUE_TO_INT (&xl, &xh, x);
+ return immed_wide_int_const (wmin, mode);
+
+ return immed_wide_int_const (real_to_integer (&x, &fail, width), mode);
break;
case UNSIGNED_FIX:
return const0_rtx;
/* Test against the unsigned upper bound. */
- if (width == HOST_BITS_PER_DOUBLE_INT)
- {
- th = -1;
- tl = -1;
- }
- else if (width >= HOST_BITS_PER_WIDE_INT)
- {
- th = ((unsigned HOST_WIDE_INT) 1
- << (width - HOST_BITS_PER_WIDE_INT)) - 1;
- tl = -1;
- }
- else
- {
- th = 0;
- tl = ((unsigned HOST_WIDE_INT) 1 << width) - 1;
- }
- real_from_integer (&t, VOIDmode, tl, th, 1);
+ wmax = wi::max_value (width, UNSIGNED);
+ real_from_integer (&t, VOIDmode, wmax, UNSIGNED);
if (REAL_VALUES_LESS (t, x))
- {
- xh = th;
- xl = tl;
- break;
- }
+ return immed_wide_int_const (wmax, mode);
- REAL_VALUE_TO_INT (&xl, &xh, x);
+ return immed_wide_int_const (real_to_integer (&x, &fail, width),
+ mode);
break;
default:
gcc_unreachable ();
}
- return immed_double_const (xl, xh, mode);
}
return NULL_RTX;
Return zero if no simplification or canonicalization is possible. */
static rtx
-simplify_byte_swapping_operation (enum rtx_code code, enum machine_mode mode,
+simplify_byte_swapping_operation (enum rtx_code code, machine_mode mode,
rtx op0, rtx op1)
{
rtx tem;
canonicalization is possible. */
static rtx
-simplify_associative_operation (enum rtx_code code, enum machine_mode mode,
+simplify_associative_operation (enum rtx_code code, machine_mode mode,
rtx op0, rtx op1)
{
rtx tem;
if (! swap_commutative_operands_p (op1, op0))
return simplify_gen_binary (code, mode, op1, op0);
- tem = op0;
- op0 = op1;
- op1 = tem;
+ std::swap (op0, op1);
}
if (GET_CODE (op0) == code)
Don't use this for relational operations such as EQ or LT.
Use simplify_relational_operation instead. */
rtx
-simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
+simplify_binary_operation (enum rtx_code code, machine_mode mode,
rtx op0, rtx op1)
{
rtx trueop0, trueop1;
/* Make sure the constant is second. */
if (GET_RTX_CLASS (code) == RTX_COMM_ARITH
&& swap_commutative_operands_p (op0, op1))
- {
- tem = op0, op0 = op1, op1 = tem;
- }
+ std::swap (op0, op1);
trueop0 = avoid_constant_pool_reference (op0);
trueop1 = avoid_constant_pool_reference (op1);
actual constants. */
static rtx
-simplify_binary_operation_1 (enum rtx_code code, enum machine_mode mode,
+simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
rtx op0, rtx op1, rtx trueop0, rtx trueop1)
{
rtx tem, reversed, opleft, opright;
if (SCALAR_INT_MODE_P (mode))
{
- double_int coeff0, coeff1;
rtx lhs = op0, rhs = op1;
- coeff0 = double_int_one;
- coeff1 = double_int_one;
+ wide_int coeff0 = wi::one (GET_MODE_PRECISION (mode));
+ wide_int coeff1 = wi::one (GET_MODE_PRECISION (mode));
if (GET_CODE (lhs) == NEG)
{
- coeff0 = double_int_minus_one;
+ coeff0 = wi::minus_one (GET_MODE_PRECISION (mode));
lhs = XEXP (lhs, 0);
}
else if (GET_CODE (lhs) == MULT
- && CONST_INT_P (XEXP (lhs, 1)))
+ && CONST_SCALAR_INT_P (XEXP (lhs, 1)))
{
- coeff0 = double_int::from_shwi (INTVAL (XEXP (lhs, 1)));
+ coeff0 = std::make_pair (XEXP (lhs, 1), mode);
lhs = XEXP (lhs, 0);
}
else if (GET_CODE (lhs) == ASHIFT
&& CONST_INT_P (XEXP (lhs, 1))
&& INTVAL (XEXP (lhs, 1)) >= 0
- && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+ && INTVAL (XEXP (lhs, 1)) < GET_MODE_PRECISION (mode))
{
- coeff0 = double_int_zero.set_bit (INTVAL (XEXP (lhs, 1)));
+ coeff0 = wi::set_bit_in_zero (INTVAL (XEXP (lhs, 1)),
+ GET_MODE_PRECISION (mode));
lhs = XEXP (lhs, 0);
}
if (GET_CODE (rhs) == NEG)
{
- coeff1 = double_int_minus_one;
+ coeff1 = wi::minus_one (GET_MODE_PRECISION (mode));
rhs = XEXP (rhs, 0);
}
else if (GET_CODE (rhs) == MULT
&& CONST_INT_P (XEXP (rhs, 1)))
{
- coeff1 = double_int::from_shwi (INTVAL (XEXP (rhs, 1)));
+ coeff1 = std::make_pair (XEXP (rhs, 1), mode);
rhs = XEXP (rhs, 0);
}
else if (GET_CODE (rhs) == ASHIFT
&& CONST_INT_P (XEXP (rhs, 1))
&& INTVAL (XEXP (rhs, 1)) >= 0
- && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+ && INTVAL (XEXP (rhs, 1)) < GET_MODE_PRECISION (mode))
{
- coeff1 = double_int_zero.set_bit (INTVAL (XEXP (rhs, 1)));
+ coeff1 = wi::set_bit_in_zero (INTVAL (XEXP (rhs, 1)),
+ GET_MODE_PRECISION (mode));
rhs = XEXP (rhs, 0);
}
{
rtx orig = gen_rtx_PLUS (mode, op0, op1);
rtx coeff;
- double_int val;
bool speed = optimize_function_for_speed_p (cfun);
- val = coeff0 + coeff1;
- coeff = immed_double_int_const (val, mode);
+ coeff = immed_wide_int_const (coeff0 + coeff1, mode);
tem = simplify_gen_binary (MULT, mode, lhs, coeff);
return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
rtx xop00 = XEXP (op0, 0);
rtx xop10 = XEXP (op1, 0);
-#ifdef HAVE_cc0
if (GET_CODE (xop00) == CC0 && GET_CODE (xop10) == CC0)
-#else
+ return xop00;
+
if (REG_P (xop00) && REG_P (xop10)
&& GET_MODE (xop00) == GET_MODE (xop10)
&& REGNO (xop00) == REGNO (xop10)
&& GET_MODE_CLASS (GET_MODE (xop00)) == MODE_CC
&& GET_MODE_CLASS (GET_MODE (xop10)) == MODE_CC)
-#endif
return xop00;
}
break;
if (SCALAR_INT_MODE_P (mode))
{
- double_int coeff0, negcoeff1;
rtx lhs = op0, rhs = op1;
- coeff0 = double_int_one;
- negcoeff1 = double_int_minus_one;
+ wide_int coeff0 = wi::one (GET_MODE_PRECISION (mode));
+ wide_int negcoeff1 = wi::minus_one (GET_MODE_PRECISION (mode));
if (GET_CODE (lhs) == NEG)
{
- coeff0 = double_int_minus_one;
+ coeff0 = wi::minus_one (GET_MODE_PRECISION (mode));
lhs = XEXP (lhs, 0);
}
else if (GET_CODE (lhs) == MULT
- && CONST_INT_P (XEXP (lhs, 1)))
+ && CONST_SCALAR_INT_P (XEXP (lhs, 1)))
{
- coeff0 = double_int::from_shwi (INTVAL (XEXP (lhs, 1)));
+ coeff0 = std::make_pair (XEXP (lhs, 1), mode);
lhs = XEXP (lhs, 0);
}
else if (GET_CODE (lhs) == ASHIFT
&& CONST_INT_P (XEXP (lhs, 1))
&& INTVAL (XEXP (lhs, 1)) >= 0
- && INTVAL (XEXP (lhs, 1)) < HOST_BITS_PER_WIDE_INT)
+ && INTVAL (XEXP (lhs, 1)) < GET_MODE_PRECISION (mode))
{
- coeff0 = double_int_zero.set_bit (INTVAL (XEXP (lhs, 1)));
+ coeff0 = wi::set_bit_in_zero (INTVAL (XEXP (lhs, 1)),
+ GET_MODE_PRECISION (mode));
lhs = XEXP (lhs, 0);
}
if (GET_CODE (rhs) == NEG)
{
- negcoeff1 = double_int_one;
+ negcoeff1 = wi::one (GET_MODE_PRECISION (mode));
rhs = XEXP (rhs, 0);
}
else if (GET_CODE (rhs) == MULT
&& CONST_INT_P (XEXP (rhs, 1)))
{
- negcoeff1 = double_int::from_shwi (-INTVAL (XEXP (rhs, 1)));
+ negcoeff1 = wi::neg (std::make_pair (XEXP (rhs, 1), mode));
rhs = XEXP (rhs, 0);
}
else if (GET_CODE (rhs) == ASHIFT
&& CONST_INT_P (XEXP (rhs, 1))
&& INTVAL (XEXP (rhs, 1)) >= 0
- && INTVAL (XEXP (rhs, 1)) < HOST_BITS_PER_WIDE_INT)
+ && INTVAL (XEXP (rhs, 1)) < GET_MODE_PRECISION (mode))
{
- negcoeff1 = double_int_zero.set_bit (INTVAL (XEXP (rhs, 1)));
+ negcoeff1 = wi::set_bit_in_zero (INTVAL (XEXP (rhs, 1)),
+ GET_MODE_PRECISION (mode));
negcoeff1 = -negcoeff1;
rhs = XEXP (rhs, 0);
}
{
rtx orig = gen_rtx_MINUS (mode, op0, op1);
rtx coeff;
- double_int val;
bool speed = optimize_function_for_speed_p (cfun);
- val = coeff0 + negcoeff1;
- coeff = immed_double_int_const (val, mode);
+ coeff = immed_wide_int_const (coeff0 + negcoeff1, mode);
tem = simplify_gen_binary (MULT, mode, lhs, coeff);
return set_src_cost (tem, speed) <= set_src_cost (orig, speed)
&& trueop1 == CONST1_RTX (mode))
return op0;
- /* Convert multiply by constant power of two into shift unless
- we are still generating RTL. This test is a kludge. */
- if (CONST_INT_P (trueop1)
- && (val = exact_log2 (UINTVAL (trueop1))) >= 0
- /* If the mode is larger than the host word size, and the
- uppermost bit is set, then this isn't a power of two due
- to implicit sign extension. */
- && (width <= HOST_BITS_PER_WIDE_INT
- || val != HOST_BITS_PER_WIDE_INT - 1))
- return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
-
- /* Likewise for multipliers wider than a word. */
- if (CONST_DOUBLE_AS_INT_P (trueop1)
- && GET_MODE (op0) == mode
- && CONST_DOUBLE_LOW (trueop1) == 0
- && (val = exact_log2 (CONST_DOUBLE_HIGH (trueop1))) >= 0
- && (val < HOST_BITS_PER_DOUBLE_INT - 1
- || GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT))
- return simplify_gen_binary (ASHIFT, mode, op0,
- GEN_INT (val + HOST_BITS_PER_WIDE_INT));
+ /* Convert multiply by constant power of two into shift. */
+ if (CONST_SCALAR_INT_P (trueop1))
+ {
+ val = wi::exact_log2 (std::make_pair (trueop1, mode));
+ if (val >= 0)
+ return simplify_gen_binary (ASHIFT, mode, op0, GEN_INT (val));
+ }
/* x*2 is x+x and x*(-1) is -x */
if (CONST_DOUBLE_AS_FLOAT_P (trueop1)
XEXP (op0, 1), mode),
op1);
+ /* Given (xor (ior (xor A B) C) D), where B, C and D are
+ constants, simplify to (xor (ior A C) (B&~C)^D), canceling
+ out bits inverted twice and not set by C. Similarly, given
+ (xor (and (xor A B) C) D), simplify without inverting C in
+ the xor operand: (xor (and A C) (B&C)^D).
+ */
+ else if ((GET_CODE (op0) == IOR || GET_CODE (op0) == AND)
+ && GET_CODE (XEXP (op0, 0)) == XOR
+ && CONST_INT_P (op1)
+ && CONST_INT_P (XEXP (op0, 1))
+ && CONST_INT_P (XEXP (XEXP (op0, 0), 1)))
+ {
+ enum rtx_code op = GET_CODE (op0);
+ rtx a = XEXP (XEXP (op0, 0), 0);
+ rtx b = XEXP (XEXP (op0, 0), 1);
+ rtx c = XEXP (op0, 1);
+ rtx d = op1;
+ HOST_WIDE_INT bval = INTVAL (b);
+ HOST_WIDE_INT cval = INTVAL (c);
+ HOST_WIDE_INT dval = INTVAL (d);
+ HOST_WIDE_INT xcval;
+
+ if (op == IOR)
+ xcval = ~cval;
+ else
+ xcval = cval;
+
+ return simplify_gen_binary (XOR, mode,
+ simplify_gen_binary (op, mode, a, c),
+ gen_int_mode ((bval & xcval) ^ dval,
+ mode));
+ }
+
/* Given (xor (and A B) C), using P^Q == (~P&Q) | (~Q&P),
we can transform like this:
(A&B)^C == ~(A&B)&C | ~C&(A&B)
HOST_WIDE_INT bval = INTVAL (b);
HOST_WIDE_INT cval = INTVAL (c);
- rtx na_c
- = simplify_binary_operation (AND, mode,
- simplify_gen_unary (NOT, mode, a, mode),
- c);
+ /* Instead of computing ~A&C, we compute its negated value,
+ ~(A|~C). If it yields -1, ~A&C is zero, so we can
+ optimize for sure. If it does not simplify, we still try
+ to compute ~A&C below, but since that always allocates
+ RTL, we don't try that before committing to returning a
+ simplified expression. */
+ rtx n_na_c = simplify_binary_operation (IOR, mode, a,
+ GEN_INT (~cval));
+
if ((~cval & bval) == 0)
{
+ rtx na_c = NULL_RTX;
+ if (n_na_c)
+ na_c = simplify_gen_unary (NOT, mode, n_na_c, mode);
+ else
+ {
+ /* If ~A does not simplify, don't bother: we don't
+ want to simplify 2 operations into 3, and if na_c
+ were to simplify with na, n_na_c would have
+ simplified as well. */
+ rtx na = simplify_unary_operation (NOT, mode, a, mode);
+ if (na)
+ na_c = simplify_gen_binary (AND, mode, na, c);
+ }
+
/* Try to simplify ~A&C | ~B&C. */
if (na_c != NULL_RTX)
return simplify_gen_binary (IOR, mode, na_c,
else
{
/* If ~A&C is zero, simplify A&(~C&B) | ~B&C. */
- if (na_c == const0_rtx)
+ if (n_na_c == CONSTM1_RTX (mode))
{
rtx a_nc_b = simplify_gen_binary (AND, mode, a,
gen_int_mode (~cval & bval,
&& (~GET_MODE_MASK (GET_MODE (XEXP (op0, 0)))
& UINTVAL (trueop1)) == 0)
{
- enum machine_mode imode = GET_MODE (XEXP (op0, 0));
+ machine_mode imode = GET_MODE (XEXP (op0, 0));
tem = simplify_gen_binary (AND, imode, XEXP (op0, 0),
gen_int_mode (INTVAL (trueop1),
imode));
if (GET_CODE (op0) == TRUNCATE && CONST_INT_P (trueop1))
{
rtx x = XEXP (op0, 0);
- enum machine_mode xmode = GET_MODE (x);
+ machine_mode xmode = GET_MODE (x);
tem = simplify_gen_binary (AND, xmode, x,
gen_int_mode (INTVAL (trueop1), xmode));
return simplify_gen_unary (TRUNCATE, mode, tem, xmode);
/* (and X (ior (not X) Y) -> (and X Y) */
if (GET_CODE (op1) == IOR
&& GET_CODE (XEXP (op1, 0)) == NOT
- && op0 == XEXP (XEXP (op1, 0), 0))
+ && rtx_equal_p (op0, XEXP (XEXP (op1, 0), 0)))
return simplify_gen_binary (AND, mode, op0, XEXP (op1, 1));
/* (and (ior (not X) Y) X) -> (and X Y) */
if (GET_CODE (op0) == IOR
&& GET_CODE (XEXP (op0, 0)) == NOT
- && op1 == XEXP (XEXP (op0, 0), 0))
+ && rtx_equal_p (op1, XEXP (XEXP (op0, 0), 0)))
return simplify_gen_binary (AND, mode, op1, XEXP (op0, 1));
+ /* (and X (ior Y (not X)) -> (and X Y) */
+ if (GET_CODE (op1) == IOR
+ && GET_CODE (XEXP (op1, 1)) == NOT
+ && rtx_equal_p (op0, XEXP (XEXP (op1, 1), 0)))
+ return simplify_gen_binary (AND, mode, op0, XEXP (op1, 0));
+
+ /* (and (ior Y (not X)) X) -> (and X Y) */
+ if (GET_CODE (op0) == IOR
+ && GET_CODE (XEXP (op0, 1)) == NOT
+ && rtx_equal_p (op1, XEXP (XEXP (op0, 1), 0)))
+ return simplify_gen_binary (AND, mode, op1, XEXP (op0, 0));
+
tem = simplify_byte_swapping_operation (code, mode, op0, op1);
if (tem)
return tem;
prefer left rotation, if op1 is from bitsize / 2 + 1 to
bitsize - 1, use other direction of rotate with 1 .. bitsize / 2 - 1
amount instead. */
+#if defined(HAVE_rotate) && defined(HAVE_rotatert)
if (CONST_INT_P (trueop1)
&& IN_RANGE (INTVAL (trueop1),
- GET_MODE_BITSIZE (mode) / 2 + (code == ROTATE),
- GET_MODE_BITSIZE (mode) - 1))
+ GET_MODE_PRECISION (mode) / 2 + (code == ROTATE),
+ GET_MODE_PRECISION (mode) - 1))
return simplify_gen_binary (code == ROTATE ? ROTATERT : ROTATE,
- mode, op0, GEN_INT (GET_MODE_BITSIZE (mode)
+ mode, op0, GEN_INT (GET_MODE_PRECISION (mode)
- INTVAL (trueop1)));
+#endif
/* FALLTHRU */
case ASHIFTRT:
if (trueop1 == CONST0_RTX (mode))
&& UINTVAL (trueop0) == GET_MODE_MASK (mode)
&& ! side_effects_p (op1))
return op0;
+ /* Given:
+ scalar modes M1, M2
+ scalar constants c1, c2
+ size (M2) > size (M1)
+ c1 == size (M2) - size (M1)
+ optimize:
+ (ashiftrt:M1 (subreg:M1 (lshiftrt:M2 (reg:M2) (const_int <c1>))
+ <low_part>)
+ (const_int <c2>))
+ to:
+ (subreg:M1 (ashiftrt:M2 (reg:M2) (const_int <c1 + c2>))
+ <low_part>). */
+ if (code == ASHIFTRT
+ && !VECTOR_MODE_P (mode)
+ && SUBREG_P (op0)
+ && CONST_INT_P (op1)
+ && GET_CODE (SUBREG_REG (op0)) == LSHIFTRT
+ && !VECTOR_MODE_P (GET_MODE (SUBREG_REG (op0)))
+ && CONST_INT_P (XEXP (SUBREG_REG (op0), 1))
+ && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
+ > GET_MODE_BITSIZE (mode))
+ && (INTVAL (XEXP (SUBREG_REG (op0), 1))
+ == (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
+ - GET_MODE_BITSIZE (mode)))
+ && subreg_lowpart_p (op0))
+ {
+ rtx tmp = GEN_INT (INTVAL (XEXP (SUBREG_REG (op0), 1))
+ + INTVAL (op1));
+ machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
+ tmp = simplify_gen_binary (ASHIFTRT,
+ GET_MODE (SUBREG_REG (op0)),
+ XEXP (SUBREG_REG (op0), 0),
+ tmp);
+ return simplify_gen_subreg (mode, tmp, inner_mode,
+ subreg_lowpart_offset (mode,
+ inner_mode));
+ }
canonicalize_shift:
if (SHIFT_COUNT_TRUNCATED && CONST_INT_P (op1))
{
- val = INTVAL (op1) & (GET_MODE_BITSIZE (mode) - 1);
+ val = INTVAL (op1) & (GET_MODE_PRECISION (mode) - 1);
if (val != INTVAL (op1))
return simplify_gen_binary (code, mode, op0, GEN_INT (val));
}
&& STORE_FLAG_VALUE == 1
&& INTVAL (trueop1) < (HOST_WIDE_INT)width)
{
- enum machine_mode imode = GET_MODE (XEXP (op0, 0));
+ machine_mode imode = GET_MODE (XEXP (op0, 0));
unsigned HOST_WIDE_INT zero_val = 0;
if (CLZ_DEFINED_VALUE_AT_ZERO (imode, zero_val)
rtx op0 = XEXP (trueop0, 0);
rtx op1 = XEXP (trueop0, 1);
- enum machine_mode opmode = GET_MODE (op0);
+ machine_mode opmode = GET_MODE (op0);
int elt_size = GET_MODE_SIZE (GET_MODE_INNER (opmode));
int n_elts = GET_MODE_SIZE (opmode) / elt_size;
rtx op00 = XEXP (op0, 0);
rtx op01 = XEXP (op0, 1);
- enum machine_mode mode00, mode01;
+ machine_mode mode00, mode01;
int n_elts00, n_elts01;
mode00 = GET_MODE (op00);
return simplify_gen_binary (VEC_CONCAT, mode, subop0, subop1);
}
+
+ /* If we select one half of a vec_concat, return that. */
+ if (GET_CODE (trueop0) == VEC_CONCAT
+ && CONST_INT_P (XVECEXP (trueop1, 0, 0)))
+ {
+ rtx subop0 = XEXP (trueop0, 0);
+ rtx subop1 = XEXP (trueop0, 1);
+ machine_mode mode0 = GET_MODE (subop0);
+ machine_mode mode1 = GET_MODE (subop1);
+ int li = GET_MODE_SIZE (GET_MODE_INNER (mode0));
+ int l0 = GET_MODE_SIZE (mode0) / li;
+ int l1 = GET_MODE_SIZE (mode1) / li;
+ int i0 = INTVAL (XVECEXP (trueop1, 0, 0));
+ if (i0 == 0 && !side_effects_p (op1) && mode == mode0)
+ {
+ bool success = true;
+ for (int i = 1; i < l0; ++i)
+ {
+ rtx j = XVECEXP (trueop1, 0, i);
+ if (!CONST_INT_P (j) || INTVAL (j) != i)
+ {
+ success = false;
+ break;
+ }
+ }
+ if (success)
+ return subop0;
+ }
+ if (i0 == l0 && !side_effects_p (op0) && mode == mode1)
+ {
+ bool success = true;
+ for (int i = 1; i < l1; ++i)
+ {
+ rtx j = XVECEXP (trueop1, 0, i);
+ if (!CONST_INT_P (j) || INTVAL (j) != i0 + i)
+ {
+ success = false;
+ break;
+ }
+ }
+ if (success)
+ return subop1;
+ }
+ }
}
if (XVECLEN (trueop1, 0) == 1
while (GET_MODE (vec) != mode
&& GET_CODE (vec) == VEC_CONCAT)
{
- HOST_WIDE_INT vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0)));
+ HOST_WIDE_INT vec_size;
+
+ if (CONST_INT_P (XEXP (vec, 0)))
+ {
+ /* vec_concat of two const_ints doesn't make sense with
+ respect to modes. */
+ if (CONST_INT_P (XEXP (vec, 1)))
+ return 0;
+
+ vec_size = GET_MODE_SIZE (GET_MODE (trueop0))
+ - GET_MODE_SIZE (GET_MODE (XEXP (vec, 1)));
+ }
+ else
+ vec_size = GET_MODE_SIZE (GET_MODE (XEXP (vec, 0)));
+
if (offset < vec_size)
vec = XEXP (vec, 0);
else
}
}
+ /* If we have two nested selects that are inverses of each
+ other, replace them with the source operand. */
+ if (GET_CODE (trueop0) == VEC_SELECT
+ && GET_MODE (XEXP (trueop0, 0)) == mode)
+ {
+ rtx op0_subop1 = XEXP (trueop0, 1);
+ gcc_assert (GET_CODE (op0_subop1) == PARALLEL);
+ gcc_assert (XVECLEN (trueop1, 0) == GET_MODE_NUNITS (mode));
+
+ /* Apply the outer ordering vector to the inner one. (The inner
+ ordering vector is expressly permitted to be of a different
+ length than the outer one.) If the result is { 0, 1, ..., n-1 }
+ then the two VEC_SELECTs cancel. */
+ for (int i = 0; i < XVECLEN (trueop1, 0); ++i)
+ {
+ rtx x = XVECEXP (trueop1, 0, i);
+ if (!CONST_INT_P (x))
+ return 0;
+ rtx y = XVECEXP (op0_subop1, 0, INTVAL (x));
+ if (!CONST_INT_P (y) || i != INTVAL (y))
+ return 0;
+ }
+ return XEXP (trueop0, 0);
+ }
+
return 0;
case VEC_CONCAT:
{
- enum machine_mode op0_mode = (GET_MODE (trueop0) != VOIDmode
+ machine_mode op0_mode = (GET_MODE (trueop0) != VOIDmode
? GET_MODE (trueop0)
: GET_MODE_INNER (mode));
- enum machine_mode op1_mode = (GET_MODE (trueop1) != VOIDmode
+ machine_mode op1_mode = (GET_MODE (trueop1) != VOIDmode
? GET_MODE (trueop1)
: GET_MODE_INNER (mode));
}
rtx
-simplify_const_binary_operation (enum rtx_code code, enum machine_mode mode,
+simplify_const_binary_operation (enum rtx_code code, machine_mode mode,
rtx op0, rtx op1)
{
- HOST_WIDE_INT arg0, arg1, arg0s, arg1s;
- HOST_WIDE_INT val;
unsigned int width = GET_MODE_PRECISION (mode);
if (VECTOR_MODE_P (mode)
&& GET_CODE (op1) == CONST_VECTOR)
{
unsigned n_elts = GET_MODE_NUNITS (mode);
- enum machine_mode op0mode = GET_MODE (op0);
+ machine_mode op0mode = GET_MODE (op0);
unsigned op0_n_elts = GET_MODE_NUNITS (op0mode);
- enum machine_mode op1mode = GET_MODE (op1);
+ machine_mode op1mode = GET_MODE (op1);
unsigned op1_n_elts = GET_MODE_NUNITS (op1mode);
rtvec v = rtvec_alloc (n_elts);
unsigned int i;
}
/* We can fold some multi-word operations. */
- if (GET_MODE_CLASS (mode) == MODE_INT
- && width == HOST_BITS_PER_DOUBLE_INT
- && (CONST_DOUBLE_AS_INT_P (op0) || CONST_INT_P (op0))
- && (CONST_DOUBLE_AS_INT_P (op1) || CONST_INT_P (op1)))
+ if ((GET_MODE_CLASS (mode) == MODE_INT
+ || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+ && CONST_SCALAR_INT_P (op0)
+ && CONST_SCALAR_INT_P (op1))
{
- double_int o0, o1, res, tmp;
+ wide_int result;
bool overflow;
-
- o0 = rtx_to_double_int (op0);
- o1 = rtx_to_double_int (op1);
-
+ rtx_mode_t pop0 = std::make_pair (op0, mode);
+ rtx_mode_t pop1 = std::make_pair (op1, mode);
+
+#if TARGET_SUPPORTS_WIDE_INT == 0
+ /* This assert keeps the simplification from producing a result
+ that cannot be represented in a CONST_DOUBLE but a lot of
+ upstream callers expect that this function never fails to
+ simplify something and so you if you added this to the test
+ above the code would die later anyway. If this assert
+ happens, you just need to make the port support wide int. */
+ gcc_assert (width <= HOST_BITS_PER_DOUBLE_INT);
+#endif
switch (code)
{
case MINUS:
- /* A - B == A + (-B). */
- o1 = -o1;
-
- /* Fall through.... */
+ result = wi::sub (pop0, pop1);
+ break;
case PLUS:
- res = o0 + o1;
+ result = wi::add (pop0, pop1);
break;
case MULT:
- res = o0 * o1;
+ result = wi::mul (pop0, pop1);
break;
case DIV:
- res = o0.divmod_with_overflow (o1, false, TRUNC_DIV_EXPR,
- &tmp, &overflow);
+ result = wi::div_trunc (pop0, pop1, SIGNED, &overflow);
if (overflow)
- return 0;
+ return NULL_RTX;
break;
case MOD:
- tmp = o0.divmod_with_overflow (o1, false, TRUNC_DIV_EXPR,
- &res, &overflow);
+ result = wi::mod_trunc (pop0, pop1, SIGNED, &overflow);
if (overflow)
- return 0;
+ return NULL_RTX;
break;
case UDIV:
- res = o0.divmod_with_overflow (o1, true, TRUNC_DIV_EXPR,
- &tmp, &overflow);
+ result = wi::div_trunc (pop0, pop1, UNSIGNED, &overflow);
if (overflow)
- return 0;
+ return NULL_RTX;
break;
case UMOD:
- tmp = o0.divmod_with_overflow (o1, true, TRUNC_DIV_EXPR,
- &res, &overflow);
+ result = wi::mod_trunc (pop0, pop1, UNSIGNED, &overflow);
if (overflow)
- return 0;
+ return NULL_RTX;
break;
case AND:
- res = o0 & o1;
+ result = wi::bit_and (pop0, pop1);
break;
case IOR:
- res = o0 | o1;
+ result = wi::bit_or (pop0, pop1);
break;
case XOR:
- res = o0 ^ o1;
+ result = wi::bit_xor (pop0, pop1);
break;
case SMIN:
- res = o0.smin (o1);
+ result = wi::smin (pop0, pop1);
break;
case SMAX:
- res = o0.smax (o1);
+ result = wi::smax (pop0, pop1);
break;
case UMIN:
- res = o0.umin (o1);
+ result = wi::umin (pop0, pop1);
break;
case UMAX:
- res = o0.umax (o1);
+ result = wi::umax (pop0, pop1);
break;
- case LSHIFTRT: case ASHIFTRT:
+ case LSHIFTRT:
+ case ASHIFTRT:
case ASHIFT:
- case ROTATE: case ROTATERT:
{
- unsigned HOST_WIDE_INT cnt;
-
+ wide_int wop1 = pop1;
if (SHIFT_COUNT_TRUNCATED)
- {
- o1.high = 0;
- o1.low &= GET_MODE_PRECISION (mode) - 1;
- }
-
- if (!o1.fits_uhwi ()
- || o1.to_uhwi () >= GET_MODE_PRECISION (mode))
- return 0;
-
- cnt = o1.to_uhwi ();
- unsigned short prec = GET_MODE_PRECISION (mode);
-
- if (code == LSHIFTRT || code == ASHIFTRT)
- res = o0.rshift (cnt, prec, code == ASHIFTRT);
- else if (code == ASHIFT)
- res = o0.alshift (cnt, prec);
- else if (code == ROTATE)
- res = o0.lrotate (cnt, prec);
- else /* code == ROTATERT */
- res = o0.rrotate (cnt, prec);
- }
- break;
-
- default:
- return 0;
- }
-
- return immed_double_int_const (res, mode);
- }
-
- if (CONST_INT_P (op0) && CONST_INT_P (op1)
- && width <= HOST_BITS_PER_WIDE_INT && width != 0)
- {
- /* Get the integer argument values in two forms:
- zero-extended in ARG0, ARG1 and sign-extended in ARG0S, ARG1S. */
-
- arg0 = INTVAL (op0);
- arg1 = INTVAL (op1);
-
- if (width < HOST_BITS_PER_WIDE_INT)
- {
- arg0 &= GET_MODE_MASK (mode);
- arg1 &= GET_MODE_MASK (mode);
-
- arg0s = arg0;
- if (val_signbit_known_set_p (mode, arg0s))
- arg0s |= ~GET_MODE_MASK (mode);
-
- arg1s = arg1;
- if (val_signbit_known_set_p (mode, arg1s))
- arg1s |= ~GET_MODE_MASK (mode);
- }
- else
- {
- arg0s = arg0;
- arg1s = arg1;
- }
-
- /* Compute the value of the arithmetic. */
-
- switch (code)
- {
- case PLUS:
- val = arg0s + arg1s;
- break;
-
- case MINUS:
- val = arg0s - arg1s;
- break;
-
- case MULT:
- val = arg0s * arg1s;
- break;
-
- case DIV:
- if (arg1s == 0
- || ((unsigned HOST_WIDE_INT) arg0s
- == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
- && arg1s == -1))
- return 0;
- val = arg0s / arg1s;
- break;
-
- case MOD:
- if (arg1s == 0
- || ((unsigned HOST_WIDE_INT) arg0s
- == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
- && arg1s == -1))
- return 0;
- val = arg0s % arg1s;
- break;
-
- case UDIV:
- if (arg1 == 0
- || ((unsigned HOST_WIDE_INT) arg0s
- == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
- && arg1s == -1))
- return 0;
- val = (unsigned HOST_WIDE_INT) arg0 / arg1;
- break;
-
- case UMOD:
- if (arg1 == 0
- || ((unsigned HOST_WIDE_INT) arg0s
- == (unsigned HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT - 1)
- && arg1s == -1))
- return 0;
- val = (unsigned HOST_WIDE_INT) arg0 % arg1;
- break;
-
- case AND:
- val = arg0 & arg1;
- break;
-
- case IOR:
- val = arg0 | arg1;
- break;
-
- case XOR:
- val = arg0 ^ arg1;
- break;
-
- case LSHIFTRT:
- case ASHIFT:
- case ASHIFTRT:
- /* Truncate the shift if SHIFT_COUNT_TRUNCATED, otherwise make sure
- the value is in range. We can't return any old value for
- out-of-range arguments because either the middle-end (via
- shift_truncation_mask) or the back-end might be relying on
- target-specific knowledge. Nor can we rely on
- shift_truncation_mask, since the shift might not be part of an
- ashlM3, lshrM3 or ashrM3 instruction. */
- if (SHIFT_COUNT_TRUNCATED)
- arg1 = (unsigned HOST_WIDE_INT) arg1 % width;
- else if (arg1 < 0 || arg1 >= GET_MODE_BITSIZE (mode))
- return 0;
-
- val = (code == ASHIFT
- ? ((unsigned HOST_WIDE_INT) arg0) << arg1
- : ((unsigned HOST_WIDE_INT) arg0) >> arg1);
+ wop1 = wi::umod_trunc (wop1, width);
+ else if (wi::geu_p (wop1, width))
+ return NULL_RTX;
- /* Sign-extend the result for arithmetic right shifts. */
- if (code == ASHIFTRT && arg0s < 0 && arg1 > 0)
- val |= HOST_WIDE_INT_M1U << (width - arg1);
- break;
+ switch (code)
+ {
+ case LSHIFTRT:
+ result = wi::lrshift (pop0, wop1);
+ break;
- case ROTATERT:
- if (arg1 < 0)
- return 0;
+ case ASHIFTRT:
+ result = wi::arshift (pop0, wop1);
+ break;
- arg1 %= width;
- val = ((((unsigned HOST_WIDE_INT) arg0) << (width - arg1))
- | (((unsigned HOST_WIDE_INT) arg0) >> arg1));
- break;
+ case ASHIFT:
+ result = wi::lshift (pop0, wop1);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ }
case ROTATE:
- if (arg1 < 0)
- return 0;
-
- arg1 %= width;
- val = ((((unsigned HOST_WIDE_INT) arg0) << arg1)
- | (((unsigned HOST_WIDE_INT) arg0) >> (width - arg1)));
- break;
-
- case COMPARE:
- /* Do nothing here. */
- return 0;
-
- case SMIN:
- val = arg0s <= arg1s ? arg0s : arg1s;
- break;
-
- case UMIN:
- val = ((unsigned HOST_WIDE_INT) arg0
- <= (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
- break;
-
- case SMAX:
- val = arg0s > arg1s ? arg0s : arg1s;
- break;
+ case ROTATERT:
+ {
+ if (wi::neg_p (pop1))
+ return NULL_RTX;
- case UMAX:
- val = ((unsigned HOST_WIDE_INT) arg0
- > (unsigned HOST_WIDE_INT) arg1 ? arg0 : arg1);
- break;
+ switch (code)
+ {
+ case ROTATE:
+ result = wi::lrotate (pop0, pop1);
+ break;
- case SS_PLUS:
- case US_PLUS:
- case SS_MINUS:
- case US_MINUS:
- case SS_MULT:
- case US_MULT:
- case SS_DIV:
- case US_DIV:
- case SS_ASHIFT:
- case US_ASHIFT:
- /* ??? There are simplifications that can be done. */
- return 0;
+ case ROTATERT:
+ result = wi::rrotate (pop0, pop1);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ }
default:
- gcc_unreachable ();
+ return NULL_RTX;
}
-
- return gen_int_mode (val, mode);
+ return immed_wide_int_const (result, mode);
}
return NULL_RTX;
\f
-/* Simplify a PLUS or MINUS, at least one of whose operands may be another
- PLUS or MINUS.
+/* Return a positive integer if X should sort after Y. The value
+ returned is 1 if and only if X and Y are both regs. */
- Rather than test for specific case, we do this by a brute-force method
- and do all possible simplifications until no more changes occur. Then
- we rebuild the operation. */
-
-struct simplify_plus_minus_op_data
-{
- rtx op;
- short neg;
-};
-
-static bool
+static int
simplify_plus_minus_op_data_cmp (rtx x, rtx y)
{
int result;
result = (commutative_operand_precedence (y)
- commutative_operand_precedence (x));
if (result)
- return result > 0;
+ return result + result;
/* Group together equal REGs to do more simplification. */
if (REG_P (x) && REG_P (y))
return REGNO (x) > REGNO (y);
- else
- return false;
+
+ return 0;
}
+/* Simplify and canonicalize a PLUS or MINUS, at least one of whose
+ operands may be another PLUS or MINUS.
+
+ Rather than test for specific case, we do this by a brute-force method
+ and do all possible simplifications until no more changes occur. Then
+ we rebuild the operation.
+
+ May return NULL_RTX when no changes were made. */
+
static rtx
-simplify_plus_minus (enum rtx_code code, enum machine_mode mode, rtx op0,
+simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0,
rtx op1)
{
- struct simplify_plus_minus_op_data ops[8];
+ struct simplify_plus_minus_op_data
+ {
+ rtx op;
+ short neg;
+ } ops[16];
rtx result, tem;
- int n_ops = 2, input_ops = 2;
- int changed, n_constants = 0, canonicalized = 0;
+ int n_ops = 2;
+ int changed, n_constants, canonicalized = 0;
int i, j;
memset (ops, 0, sizeof ops);
do
{
changed = 0;
+ n_constants = 0;
for (i = 0; i < n_ops; i++)
{
{
case PLUS:
case MINUS:
- if (n_ops == 7)
+ if (n_ops == ARRAY_SIZE (ops))
return NULL_RTX;
ops[n_ops].op = XEXP (this_op, 1);
n_ops++;
ops[i].op = XEXP (this_op, 0);
- input_ops++;
changed = 1;
- canonicalized |= this_neg;
+ /* If this operand was negated then we will potentially
+ canonicalize the expression. Similarly if we don't
+ place the operands adjacent we're re-ordering the
+ expression and thus might be performing a
+ canonicalization. Ignore register re-ordering.
+ ??? It might be better to shuffle the ops array here,
+ but then (plus (plus (A, B), plus (C, D))) wouldn't
+ be seen as non-canonical. */
+ if (this_neg
+ || (i != n_ops - 2
+ && !(REG_P (ops[i].op) && REG_P (ops[n_ops - 1].op))))
+ canonicalized = 1;
break;
case NEG:
break;
case CONST:
- if (n_ops < 7
+ if (n_ops != ARRAY_SIZE (ops)
&& GET_CODE (XEXP (this_op, 0)) == PLUS
&& CONSTANT_P (XEXP (XEXP (this_op, 0), 0))
&& CONSTANT_P (XEXP (XEXP (this_op, 0), 1)))
ops[n_ops].neg = this_neg;
n_ops++;
changed = 1;
- canonicalized = 1;
+ canonicalized = 1;
}
break;
case NOT:
/* ~a -> (-a - 1) */
- if (n_ops != 7)
+ if (n_ops != ARRAY_SIZE (ops))
{
ops[n_ops].op = CONSTM1_RTX (mode);
ops[n_ops++].neg = this_neg;
ops[i].op = XEXP (this_op, 0);
ops[i].neg = !this_neg;
changed = 1;
- canonicalized = 1;
+ canonicalized = 1;
}
break;
ops[i].op = neg_const_int (mode, this_op);
ops[i].neg = 0;
changed = 1;
- canonicalized = 1;
+ canonicalized = 1;
}
break;
}
/* Now simplify each pair of operands until nothing changes. */
- do
+ while (1)
{
- /* Insertion sort is good enough for an eight-element array. */
+ /* Insertion sort is good enough for a small array. */
for (i = 1; i < n_ops; i++)
- {
- struct simplify_plus_minus_op_data save;
- j = i - 1;
- if (!simplify_plus_minus_op_data_cmp (ops[j].op, ops[i].op))
+ {
+ struct simplify_plus_minus_op_data save;
+ int cmp;
+
+ j = i - 1;
+ cmp = simplify_plus_minus_op_data_cmp (ops[j].op, ops[i].op);
+ if (cmp <= 0)
continue;
+ /* Just swapping registers doesn't count as canonicalization. */
+ if (cmp != 1)
+ canonicalized = 1;
- canonicalized = 1;
- save = ops[i];
- do
+ save = ops[i];
+ do
ops[j + 1] = ops[j];
- while (j-- && simplify_plus_minus_op_data_cmp (ops[j].op, save.op));
- ops[j + 1] = save;
- }
+ while (j--
+ && simplify_plus_minus_op_data_cmp (ops[j].op, save.op) > 0);
+ ops[j + 1] = save;
+ }
changed = 0;
for (i = n_ops - 1; i > 0; i--)
{
ncode = MINUS;
if (lneg)
- tem = lhs, lhs = rhs, rhs = tem;
+ std::swap (lhs, rhs);
}
else if (swap_commutative_operands_p (lhs, rhs))
- tem = lhs, lhs = rhs, rhs = tem;
+ std::swap (lhs, rhs);
if ((GET_CODE (lhs) == CONST || CONST_INT_P (lhs))
&& (GET_CODE (rhs) == CONST || CONST_INT_P (rhs)))
tem_lhs = GET_CODE (lhs) == CONST ? XEXP (lhs, 0) : lhs;
tem_rhs = GET_CODE (rhs) == CONST ? XEXP (rhs, 0) : rhs;
- tem = simplify_binary_operation (ncode, mode, tem_lhs, tem_rhs);
+ tem = simplify_binary_operation (ncode, mode, tem_lhs,
+ tem_rhs);
if (tem && !CONSTANT_P (tem))
tem = gen_rtx_CONST (GET_MODE (tem), tem);
else
tem = simplify_binary_operation (ncode, mode, lhs, rhs);
- /* Reject "simplifications" that just wrap the two
- arguments in a CONST. Failure to do so can result
- in infinite recursion with simplify_binary_operation
- when it calls us to simplify CONST operations. */
- if (tem
- && ! (GET_CODE (tem) == CONST
- && GET_CODE (XEXP (tem, 0)) == ncode
- && XEXP (XEXP (tem, 0), 0) == lhs
- && XEXP (XEXP (tem, 0), 1) == rhs))
+ if (tem)
{
+ /* Reject "simplifications" that just wrap the two
+ arguments in a CONST. Failure to do so can result
+ in infinite recursion with simplify_binary_operation
+ when it calls us to simplify CONST operations.
+ Also, if we find such a simplification, don't try
+ any more combinations with this rhs: We must have
+ something like symbol+offset, ie. one of the
+ trivial CONST expressions we handle later. */
+ if (GET_CODE (tem) == CONST
+ && GET_CODE (XEXP (tem, 0)) == ncode
+ && XEXP (XEXP (tem, 0), 0) == lhs
+ && XEXP (XEXP (tem, 0), 1) == rhs)
+ break;
lneg &= rneg;
if (GET_CODE (tem) == NEG)
tem = XEXP (tem, 0), lneg = !lneg;
}
}
- /* If nothing changed, fail. */
- if (!canonicalized)
- return NULL_RTX;
+ if (!changed)
+ break;
/* Pack all the operands to the lower-numbered entries. */
for (i = 0, j = 0; j < n_ops; j++)
- if (ops[j].op)
- {
+ if (ops[j].op)
+ {
ops[i] = ops[j];
i++;
- }
+ }
n_ops = i;
}
- while (changed);
+
+ /* If nothing changed, fail. */
+ if (!canonicalized)
+ return NULL_RTX;
/* Create (minus -C X) instead of (neg (const (plus X C))). */
if (n_ops == 2
the operands or, if both are VOIDmode, the operands are compared in
"infinite precision". */
rtx
-simplify_relational_operation (enum rtx_code code, enum machine_mode mode,
- enum machine_mode cmp_mode, rtx op0, rtx op1)
+simplify_relational_operation (enum rtx_code code, machine_mode mode,
+ machine_mode cmp_mode, rtx op0, rtx op1)
{
rtx tem, trueop0, trueop1;
/* For the following tests, ensure const0_rtx is op1. */
if (swap_commutative_operands_p (op0, op1)
|| (op0 == const0_rtx && op1 != const0_rtx))
- tem = op0, op0 = op1, op1 = tem, code = swap_condition (code);
+ std::swap (op0, op1), code = swap_condition (code);
/* If op0 is a compare, extract the comparison arguments from it. */
if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
mode the comparison is done in, so it is the mode of the operands. */
static rtx
-simplify_relational_operation_1 (enum rtx_code code, enum machine_mode mode,
- enum machine_mode cmp_mode, rtx op0, rtx op1)
+simplify_relational_operation_1 (enum rtx_code code, machine_mode mode,
+ machine_mode cmp_mode, rtx op0, rtx op1)
{
enum rtx_code op0code = GET_CODE (op0);
&& op0code == XOR
&& rtx_equal_p (XEXP (op0, 0), op1)
&& !side_effects_p (XEXP (op0, 0)))
- return simplify_gen_relational (code, mode, cmp_mode,
- XEXP (op0, 1), const0_rtx);
+ return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 1),
+ CONST0_RTX (mode));
/* Likewise (eq/ne (xor x y) y) simplifies to (eq/ne x 0). */
if ((code == EQ || code == NE)
&& op0code == XOR
&& rtx_equal_p (XEXP (op0, 1), op1)
&& !side_effects_p (XEXP (op0, 1)))
- return simplify_gen_relational (code, mode, cmp_mode,
- XEXP (op0, 0), const0_rtx);
+ return simplify_gen_relational (code, mode, cmp_mode, XEXP (op0, 0),
+ CONST0_RTX (mode));
/* (eq/ne (xor x C1) C2) simplifies to (eq/ne x (C1^C2)). */
if ((code == EQ || code == NE)
simplify_gen_binary (XOR, cmp_mode,
XEXP (op0, 1), op1));
+ /* (eq/ne (and x y) x) simplifies to (eq/ne (and (not y) x) 0), which
+ can be implemented with a BICS instruction on some targets, or
+ constant-folded if y is a constant. */
+ if ((code == EQ || code == NE)
+ && op0code == AND
+ && rtx_equal_p (XEXP (op0, 0), op1)
+ && !side_effects_p (op1)
+ && op1 != CONST0_RTX (cmp_mode))
+ {
+ rtx not_y = simplify_gen_unary (NOT, cmp_mode, XEXP (op0, 1), cmp_mode);
+ rtx lhs = simplify_gen_binary (AND, cmp_mode, not_y, XEXP (op0, 0));
+
+ return simplify_gen_relational (code, mode, cmp_mode, lhs,
+ CONST0_RTX (cmp_mode));
+ }
+
+ /* Likewise for (eq/ne (and x y) y). */
+ if ((code == EQ || code == NE)
+ && op0code == AND
+ && rtx_equal_p (XEXP (op0, 1), op1)
+ && !side_effects_p (op1)
+ && op1 != CONST0_RTX (cmp_mode))
+ {
+ rtx not_x = simplify_gen_unary (NOT, cmp_mode, XEXP (op0, 0), cmp_mode);
+ rtx lhs = simplify_gen_binary (AND, cmp_mode, not_x, XEXP (op0, 1));
+
+ return simplify_gen_relational (code, mode, cmp_mode, lhs,
+ CONST0_RTX (cmp_mode));
+ }
+
/* (eq/ne (bswap x) C1) simplifies to (eq/ne x C2) with C2 swapped. */
if ((code == EQ || code == NE)
&& GET_CODE (op0) == BSWAP
}
}
-/* Check if the given comparison (done in the given MODE) is actually a
- tautology or a contradiction.
- If no simplification is possible, this function returns zero.
- Otherwise, it returns either const_true_rtx or const0_rtx. */
+/* Check if the given comparison (done in the given MODE) is actually
+ a tautology or a contradiction. If the mode is VOID_mode, the
+ comparison is done in "infinite precision". If no simplification
+ is possible, this function returns zero. Otherwise, it returns
+ either const_true_rtx or const0_rtx. */
rtx
simplify_const_relational_operation (enum rtx_code code,
- enum machine_mode mode,
+ machine_mode mode,
rtx op0, rtx op1)
{
rtx tem;
/* Make sure the constant is second. */
if (swap_commutative_operands_p (op0, op1))
{
- tem = op0, op0 = op1, op1 = tem;
+ std::swap (op0, op1);
code = swap_condition (code);
}
result except if they have side-effects. Even with NaNs we know
the result of unordered comparisons and, if signaling NaNs are
irrelevant, also the result of LT/GT/LTGT. */
- if ((! HONOR_NANS (GET_MODE (trueop0))
+ if ((! HONOR_NANS (trueop0)
|| code == UNEQ || code == UNLE || code == UNGE
|| ((code == LT || code == GT || code == LTGT)
- && ! HONOR_SNANS (GET_MODE (trueop0))))
+ && ! HONOR_SNANS (trueop0)))
&& rtx_equal_p (trueop0, trueop1)
&& ! side_effects_p (trueop0))
return comparison_result (code, CMP_EQ);
/* Otherwise, see if the operands are both integers. */
if ((GET_MODE_CLASS (mode) == MODE_INT || mode == VOIDmode)
- && (CONST_DOUBLE_AS_INT_P (trueop0) || CONST_INT_P (trueop0))
- && (CONST_DOUBLE_AS_INT_P (trueop1) || CONST_INT_P (trueop1)))
+ && CONST_SCALAR_INT_P (trueop0) && CONST_SCALAR_INT_P (trueop1))
{
- int width = GET_MODE_PRECISION (mode);
- HOST_WIDE_INT l0s, h0s, l1s, h1s;
- unsigned HOST_WIDE_INT l0u, h0u, l1u, h1u;
-
- /* Get the two words comprising each integer constant. */
- if (CONST_DOUBLE_AS_INT_P (trueop0))
- {
- l0u = l0s = CONST_DOUBLE_LOW (trueop0);
- h0u = h0s = CONST_DOUBLE_HIGH (trueop0);
- }
- else
- {
- l0u = l0s = INTVAL (trueop0);
- h0u = h0s = HWI_SIGN_EXTEND (l0s);
- }
-
- if (CONST_DOUBLE_AS_INT_P (trueop1))
- {
- l1u = l1s = CONST_DOUBLE_LOW (trueop1);
- h1u = h1s = CONST_DOUBLE_HIGH (trueop1);
- }
- else
- {
- l1u = l1s = INTVAL (trueop1);
- h1u = h1s = HWI_SIGN_EXTEND (l1s);
- }
-
- /* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
- we have to sign or zero-extend the values. */
- if (width != 0 && width < HOST_BITS_PER_WIDE_INT)
- {
- l0u &= GET_MODE_MASK (mode);
- l1u &= GET_MODE_MASK (mode);
-
- if (val_signbit_known_set_p (mode, l0s))
- l0s |= ~GET_MODE_MASK (mode);
-
- if (val_signbit_known_set_p (mode, l1s))
- l1s |= ~GET_MODE_MASK (mode);
- }
- if (width != 0 && width <= HOST_BITS_PER_WIDE_INT)
- h0u = h1u = 0, h0s = HWI_SIGN_EXTEND (l0s), h1s = HWI_SIGN_EXTEND (l1s);
-
- if (h0u == h1u && l0u == l1u)
+ /* It would be nice if we really had a mode here. However, the
+ largest int representable on the target is as good as
+ infinite. */
+ machine_mode cmode = (mode == VOIDmode) ? MAX_MODE_INT : mode;
+ rtx_mode_t ptrueop0 = std::make_pair (trueop0, cmode);
+ rtx_mode_t ptrueop1 = std::make_pair (trueop1, cmode);
+
+ if (wi::eq_p (ptrueop0, ptrueop1))
return comparison_result (code, CMP_EQ);
else
{
- int cr;
- cr = (h0s < h1s || (h0s == h1s && l0u < l1u)) ? CMP_LT : CMP_GT;
- cr |= (h0u < h1u || (h0u == h1u && l0u < l1u)) ? CMP_LTU : CMP_GTU;
+ int cr = wi::lts_p (ptrueop0, ptrueop1) ? CMP_LT : CMP_GT;
+ cr |= wi::ltu_p (ptrueop0, ptrueop1) ? CMP_LTU : CMP_GTU;
return comparison_result (code, cr);
}
}
a constant. Return 0 if no simplifications is possible. */
rtx
-simplify_ternary_operation (enum rtx_code code, enum machine_mode mode,
- enum machine_mode op0_mode, rtx op0, rtx op1,
+simplify_ternary_operation (enum rtx_code code, machine_mode mode,
+ machine_mode op0_mode, rtx op0, rtx op1,
rtx op2)
{
unsigned int width = GET_MODE_PRECISION (mode);
/* Canonicalize the two multiplication operands. */
/* a * -b + c => -b * a + c. */
if (swap_commutative_operands_p (op0, op1))
- tem = op0, op0 = op1, op1 = tem, any_change = true;
+ std::swap (op0, op1), any_change = true;
if (any_change)
return gen_rtx_FMA (mode, op0, op1, op2);
if (COMPARISON_P (op0) && ! side_effects_p (op0))
{
- enum machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
+ machine_mode cmp_mode = (GET_MODE (XEXP (op0, 0)) == VOIDmode
? GET_MODE (XEXP (op0, 1))
: GET_MODE (XEXP (op0, 0)));
rtx temp;
op0, XEXP (op1, 0), op2);
}
}
+
+ /* Replace (vec_merge (vec_duplicate (vec_select a parallel (i))) a 1 << i)
+ with a. */
+ if (GET_CODE (op0) == VEC_DUPLICATE
+ && GET_CODE (XEXP (op0, 0)) == VEC_SELECT
+ && GET_CODE (XEXP (XEXP (op0, 0), 1)) == PARALLEL
+ && mode_nunits[GET_MODE (XEXP (op0, 0))] == 1)
+ {
+ tem = XVECEXP ((XEXP (XEXP (op0, 0), 1)), 0, 0);
+ if (CONST_INT_P (tem) && CONST_INT_P (op2))
+ {
+ if (XEXP (XEXP (op0, 0), 0) == op1
+ && UINTVAL (op2) == HOST_WIDE_INT_1U << UINTVAL (tem))
+ return op1;
+ }
+ }
}
if (rtx_equal_p (op0, op1)
return 0;
}
-/* Evaluate a SUBREG of a CONST_INT or CONST_DOUBLE or CONST_FIXED
- or CONST_VECTOR,
- returning another CONST_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR.
+/* Evaluate a SUBREG of a CONST_INT or CONST_WIDE_INT or CONST_DOUBLE
+ or CONST_FIXED or CONST_VECTOR, returning another CONST_INT or
+ CONST_WIDE_INT or CONST_DOUBLE or CONST_FIXED or CONST_VECTOR.
Works by unpacking OP into a collection of 8-bit values
represented as a little-endian array of 'unsigned char', selecting by BYTE,
and then repacking them again for OUTERMODE. */
static rtx
-simplify_immed_subreg (enum machine_mode outermode, rtx op,
- enum machine_mode innermode, unsigned int byte)
+simplify_immed_subreg (machine_mode outermode, rtx op,
+ machine_mode innermode, unsigned int byte)
{
- /* We support up to 512-bit values (for V8DFmode). */
enum {
- max_bitsize = 512,
value_bit = 8,
value_mask = (1 << value_bit) - 1
};
- unsigned char value[max_bitsize / value_bit];
+ unsigned char value[MAX_BITSIZE_MODE_ANY_MODE / value_bit];
int value_start;
int i;
int elem;
rtx result_s;
rtvec result_v = NULL;
enum mode_class outer_class;
- enum machine_mode outer_submode;
+ machine_mode outer_submode;
+ int max_bitsize;
/* Some ports misuse CCmode. */
if (GET_MODE_CLASS (outermode) == MODE_CC && CONST_INT_P (op))
if (COMPLEX_MODE_P (outermode))
return NULL_RTX;
+ /* We support any size mode. */
+ max_bitsize = MAX (GET_MODE_BITSIZE (outermode),
+ GET_MODE_BITSIZE (innermode));
+
/* Unpack the value. */
if (GET_CODE (op) == CONST_VECTOR)
*vp++ = INTVAL (el) < 0 ? -1 : 0;
break;
+ case CONST_WIDE_INT:
+ {
+ rtx_mode_t val = std::make_pair (el, innermode);
+ unsigned char extend = wi::sign_mask (val);
+
+ for (i = 0; i < elem_bitsize; i += value_bit)
+ *vp++ = wi::extract_uhwi (val, i, value_bit);
+ for (; i < elem_bitsize; i += value_bit)
+ *vp++ = extend;
+ }
+ break;
+
case CONST_DOUBLE:
- if (GET_MODE (el) == VOIDmode)
+ if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (el) == VOIDmode)
{
unsigned char extend = 0;
/* If this triggers, someone should have generated a
}
else
{
- long tmp[max_bitsize / 32];
+ /* This is big enough for anything on the platform. */
+ long tmp[MAX_BITSIZE_MODE_ANY_MODE / 32];
int bitsize = GET_MODE_BITSIZE (GET_MODE (el));
gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (el)));
case MODE_INT:
case MODE_PARTIAL_INT:
{
- unsigned HOST_WIDE_INT hi = 0, lo = 0;
-
- for (i = 0;
- i < HOST_BITS_PER_WIDE_INT && i < elem_bitsize;
- i += value_bit)
- lo |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
- for (; i < elem_bitsize; i += value_bit)
- hi |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask)
- << (i - HOST_BITS_PER_WIDE_INT);
-
- /* immed_double_const doesn't call trunc_int_for_mode. I don't
- know why. */
- if (elem_bitsize <= HOST_BITS_PER_WIDE_INT)
- elems[elem] = gen_int_mode (lo, outer_submode);
- else if (elem_bitsize <= HOST_BITS_PER_DOUBLE_INT)
- elems[elem] = immed_double_const (lo, hi, outer_submode);
- else
+ int u;
+ int base = 0;
+ int units
+ = (GET_MODE_BITSIZE (outer_submode) + HOST_BITS_PER_WIDE_INT - 1)
+ / HOST_BITS_PER_WIDE_INT;
+ HOST_WIDE_INT tmp[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
+ wide_int r;
+
+ if (GET_MODE_PRECISION (outer_submode) > MAX_BITSIZE_MODE_ANY_INT)
+ return NULL_RTX;
+ for (u = 0; u < units; u++)
+ {
+ unsigned HOST_WIDE_INT buf = 0;
+ for (i = 0;
+ i < HOST_BITS_PER_WIDE_INT && base + i < elem_bitsize;
+ i += value_bit)
+ buf |= (unsigned HOST_WIDE_INT)(*vp++ & value_mask) << i;
+
+ tmp[u] = buf;
+ base += HOST_BITS_PER_WIDE_INT;
+ }
+ r = wide_int::from_array (tmp, units,
+ GET_MODE_PRECISION (outer_submode));
+#if TARGET_SUPPORTS_WIDE_INT == 0
+ /* Make sure r will fit into CONST_INT or CONST_DOUBLE. */
+ if (wi::min_precision (r, SIGNED) > HOST_BITS_PER_DOUBLE_INT)
return NULL_RTX;
+#endif
+ elems[elem] = immed_wide_int_const (r, outer_submode);
}
break;
case MODE_DECIMAL_FLOAT:
{
REAL_VALUE_TYPE r;
- long tmp[max_bitsize / 32];
+ long tmp[MAX_BITSIZE_MODE_ANY_MODE / 32];
/* real_from_target wants its input in words affected by
FLOAT_WORDS_BIG_ENDIAN. However, we ignore this,
/* Simplify SUBREG:OUTERMODE(OP:INNERMODE, BYTE)
Return 0 if no simplifications are possible. */
rtx
-simplify_subreg (enum machine_mode outermode, rtx op,
- enum machine_mode innermode, unsigned int byte)
+simplify_subreg (machine_mode outermode, rtx op,
+ machine_mode innermode, unsigned int byte)
{
/* Little bit of sanity checking. */
gcc_assert (innermode != VOIDmode);
or not at all if changing back op starting mode. */
if (GET_CODE (op) == SUBREG)
{
- enum machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
+ machine_mode innermostmode = GET_MODE (SUBREG_REG (op));
int final_offset = byte + SUBREG_BYTE (op);
rtx newx;
{
newx = gen_rtx_SUBREG (outermode, SUBREG_REG (op), final_offset);
if (SUBREG_PROMOTED_VAR_P (op)
- && SUBREG_PROMOTED_UNSIGNED_P (op) >= 0
+ && SUBREG_PROMOTED_SIGN (op) >= 0
&& GET_MODE_CLASS (outermode) == MODE_INT
&& IN_RANGE (GET_MODE_SIZE (outermode),
GET_MODE_SIZE (innermode),
&& subreg_lowpart_p (newx))
{
SUBREG_PROMOTED_VAR_P (newx) = 1;
- SUBREG_PROMOTED_UNSIGNED_SET
- (newx, SUBREG_PROMOTED_UNSIGNED_P (op));
+ SUBREG_PROMOTED_SET (newx, SUBREG_PROMOTED_GET (op));
}
return newx;
}
/* Make a SUBREG operation or equivalent if it folds. */
rtx
-simplify_gen_subreg (enum machine_mode outermode, rtx op,
- enum machine_mode innermode, unsigned int byte)
+simplify_gen_subreg (machine_mode outermode, rtx op,
+ machine_mode innermode, unsigned int byte)
{
rtx newx;
simplify_rtx (const_rtx x)
{
const enum rtx_code code = GET_CODE (x);
- const enum machine_mode mode = GET_MODE (x);
+ const machine_mode mode = GET_MODE (x);
switch (GET_RTX_CLASS (code))
{