summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/double-int.c35
-rw-r--r--gcc/double-int.h28
-rw-r--r--gcc/expmed.c56
-rw-r--r--gcc/fold-const.c72
-rw-r--r--gcc/tree.c24
-rw-r--r--gcc/tree.h4
7 files changed, 112 insertions, 123 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b09f10f51b0..35a16333038 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,19 @@
+2010-04-15 Anatoly Sokolov <aesok@post.ru>
+
+ * double-int.h (HOST_BITS_PER_DOUBLE_INT): Define.
+ (double_int_not, double_int_lshift, double_int_rshift): Declare.
+ (double_int_negative_p): Convert to static inline function.
+ * double-int.c (double_int_lshift, double_int_lshift): Add new function.
+ (double_int_negative_p): Remove.
+ * tree.h (lshift_double, rshift_double):
+ * tree.c (build_low_bits_mask): Clean up, use double_int_* functions.
+ * fold-const.c (fold_convert_const_int_from_real,
+ fold_convert_const_int_from_fixed, div_if_zero_remainder): (Ditto.).
+ (lshift_double): Change type of arith argument to bool.
+ (rshift_double): Change type of arith argument to bool. Correct
+ comment.
+ * expmed.c (mask_rtx, lshift_value): (Ditto.).
+
2010-04-14 Bernd Schmidt <bernd.schmidt@codesourcery.com>
PR target/21803
diff --git a/gcc/double-int.c b/gcc/double-int.c
index a49ce473a7e..1a746814598 100644
--- a/gcc/double-int.c
+++ b/gcc/double-int.c
@@ -1,5 +1,5 @@
/* Operations with long integers.
- Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
This file is part of GCC.
@@ -290,6 +290,30 @@ double_int_umod (double_int a, double_int b, unsigned code)
return double_int_mod (a, b, true, code);
}
+/* Shift A left by COUNT places keeping only PREC bits of result. Shift
+ right if COUNT is negative. ARITH true specifies arithmetic shifting;
+ otherwise use logical shift. */
+
+double_int
+double_int_lshift (double_int a, HOST_WIDE_INT count, unsigned int prec, bool arith)
+{
+ double_int ret;
+ lshift_double (a.low, a.high, count, prec, &ret.low, &ret.high, arith);
+ return ret;
+}
+
+/* Shift A rigth by COUNT places keeping only PREC bits of result. Shift
+ left if COUNT is negative. ARITH true specifies arithmetic shifting;
+ otherwise use logical shift. */
+
+double_int
+double_int_rshift (double_int a, HOST_WIDE_INT count, unsigned int prec, bool arith)
+{
+ double_int ret;
+ rshift_double (a.low, a.high, count, prec, &ret.low, &ret.high, arith);
+ return ret;
+}
+
/* Constructs tree in type TYPE from with value given by CST. Signedness of CST
is assumed to be the same as the signedness of TYPE. */
@@ -314,15 +338,6 @@ double_int_fits_to_tree_p (const_tree type, double_int cst)
return double_int_equal_p (cst, ext);
}
-/* Returns true if CST is negative. Of course, CST is considered to
- be signed. */
-
-bool
-double_int_negative_p (double_int cst)
-{
- return cst.high < 0;
-}
-
/* Returns -1 if A < B, 0 if A == B and 1 if A > B. Signedness of the
comparison is given by UNS. */
diff --git a/gcc/double-int.h b/gcc/double-int.h
index 84185890e29..30e32fcde13 100644
--- a/gcc/double-int.h
+++ b/gcc/double-int.h
@@ -1,5 +1,5 @@
/* Operations with long integers.
- Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
This file is part of GCC.
@@ -57,6 +57,8 @@ typedef struct
HOST_WIDE_INT high;
} double_int;
+#define HOST_BITS_PER_DOUBLE_INT (2 * HOST_BITS_PER_WIDE_INT)
+
union tree_node;
/* Constructors and conversions. */
@@ -127,7 +129,29 @@ double_int double_int_umod (double_int, double_int, unsigned);
double_int double_int_divmod (double_int, double_int, bool, unsigned, double_int *);
double_int double_int_sdivmod (double_int, double_int, unsigned, double_int *);
double_int double_int_udivmod (double_int, double_int, unsigned, double_int *);
-bool double_int_negative_p (double_int);
+
+/* Logical operations. */
+static inline double_int
+double_int_not (double_int a)
+{
+ a.low = ~a.low;
+ a.high = ~ a.high;
+ return a;
+}
+
+/* Shift operations. */
+double_int double_int_lshift (double_int, HOST_WIDE_INT, unsigned int, bool);
+double_int double_int_rshift (double_int, HOST_WIDE_INT, unsigned int, bool);
+
+/* Returns true if CST is negative. Of course, CST is considered to
+ be signed. */
+
+static inline bool
+double_int_negative_p (double_int cst)
+{
+ return cst.high < 0;
+}
+
int double_int_cmp (double_int, double_int, bool);
int double_int_scmp (double_int, double_int);
int double_int_ucmp (double_int, double_int);
diff --git a/gcc/expmed.c b/gcc/expmed.c
index aa2409942d9..44de4a6512e 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -1839,39 +1839,15 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
static rtx
mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
{
- HOST_WIDE_INT masklow, maskhigh;
+ double_int mask;
- if (bitsize == 0)
- masklow = 0;
- else if (bitpos < HOST_BITS_PER_WIDE_INT)
- masklow = (HOST_WIDE_INT) -1 << bitpos;
- else
- masklow = 0;
-
- if (bitpos + bitsize < HOST_BITS_PER_WIDE_INT)
- masklow &= ((unsigned HOST_WIDE_INT) -1
- >> (HOST_BITS_PER_WIDE_INT - bitpos - bitsize));
-
- if (bitpos <= HOST_BITS_PER_WIDE_INT)
- maskhigh = -1;
- else
- maskhigh = (HOST_WIDE_INT) -1 << (bitpos - HOST_BITS_PER_WIDE_INT);
-
- if (bitsize == 0)
- maskhigh = 0;
- else if (bitpos + bitsize > HOST_BITS_PER_WIDE_INT)
- maskhigh &= ((unsigned HOST_WIDE_INT) -1
- >> (2 * HOST_BITS_PER_WIDE_INT - bitpos - bitsize));
- else
- maskhigh = 0;
+ mask = double_int_mask (bitsize);
+ mask = double_int_lshift (mask, bitpos, HOST_BITS_PER_DOUBLE_INT, false);
if (complement)
- {
- maskhigh = ~maskhigh;
- masklow = ~masklow;
- }
+ mask = double_int_not (mask);
- return immed_double_const (masklow, maskhigh, mode);
+ return immed_double_const (mask.low, mask.high, mode);
}
/* Return a constant integer (CONST_INT or CONST_DOUBLE) rtx with the value
@@ -1880,24 +1856,12 @@ mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
static rtx
lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
{
- unsigned HOST_WIDE_INT v = INTVAL (value);
- HOST_WIDE_INT low, high;
-
- if (bitsize < HOST_BITS_PER_WIDE_INT)
- v &= ~((HOST_WIDE_INT) -1 << bitsize);
-
- if (bitpos < HOST_BITS_PER_WIDE_INT)
- {
- low = v << bitpos;
- high = (bitpos > 0 ? (v >> (HOST_BITS_PER_WIDE_INT - bitpos)) : 0);
- }
- else
- {
- low = 0;
- high = v << (bitpos - HOST_BITS_PER_WIDE_INT);
- }
+ double_int val;
+
+ val = double_int_zext (uhwi_to_double_int (INTVAL (value)), bitsize);
+ val = double_int_lshift (val, bitpos, HOST_BITS_PER_DOUBLE_INT, false);
- return immed_double_const (low, high, mode);
+ return immed_double_const (val.low, val.high, mode);
}
/* Extract a bit field that is split across two words
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 34e5874eadd..c3fcaa58c96 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -436,7 +436,7 @@ mul_double_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
void
lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
HOST_WIDE_INT count, unsigned int prec,
- unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, int arith)
+ unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, bool arith)
{
unsigned HOST_WIDE_INT signmask;
@@ -491,7 +491,7 @@ lshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
}
/* Shift the doubleword integer in L1, H1 right by COUNT places
- keeping only PREC bits of result. COUNT must be positive.
+ keeping only PREC bits of result. Shift left if COUNT is negative.
ARITH nonzero specifies arithmetic shifting; otherwise use logical shift.
Store the value as two `HOST_WIDE_INT' pieces in *LV and *HV. */
@@ -499,7 +499,7 @@ void
rshift_double (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
HOST_WIDE_INT count, unsigned int prec,
unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv,
- int arith)
+ bool arith)
{
unsigned HOST_WIDE_INT signmask;
@@ -881,10 +881,7 @@ div_and_round_double (enum tree_code code, int uns,
tree
div_if_zero_remainder (enum tree_code code, const_tree arg1, const_tree arg2)
{
- unsigned HOST_WIDE_INT int1l, int2l;
- HOST_WIDE_INT int1h, int2h;
- unsigned HOST_WIDE_INT quol, reml;
- HOST_WIDE_INT quoh, remh;
+ double_int quo, rem;
int uns;
/* The sign of the division is according to operand two, that
@@ -895,17 +892,14 @@ div_if_zero_remainder (enum tree_code code, const_tree arg1, const_tree arg2)
&& TYPE_IS_SIZETYPE (TREE_TYPE (arg2)))
uns = false;
- int1l = TREE_INT_CST_LOW (arg1);
- int1h = TREE_INT_CST_HIGH (arg1);
- int2l = TREE_INT_CST_LOW (arg2);
- int2h = TREE_INT_CST_HIGH (arg2);
+ quo = double_int_divmod (tree_to_double_int (arg1),
+ tree_to_double_int (arg2),
+ uns, code, &rem);
- div_and_round_double (code, uns, int1l, int1h, int2l, int2h,
- &quol, &quoh, &reml, &remh);
- if (remh != 0 || reml != 0)
- return NULL_TREE;
+ if (double_int_zero_p (rem))
+ return build_int_cst_wide (TREE_TYPE (arg1), quo.low, quo.high);
- return build_int_cst_wide (TREE_TYPE (arg1), quol, quoh);
+ return NULL_TREE;
}
/* This is nonzero if we should defer warnings about undefined
@@ -2279,7 +2273,7 @@ fold_convert_const_int_from_real (enum tree_code code, tree type, const_tree arg
C and C++ standards that simply state that the behavior of
FP-to-integer conversion is unspecified upon overflow. */
- HOST_WIDE_INT high, low;
+ double_int val;
REAL_VALUE_TYPE r;
REAL_VALUE_TYPE x = TREE_REAL_CST (arg1);
@@ -2297,8 +2291,7 @@ fold_convert_const_int_from_real (enum tree_code code, tree type, const_tree arg
if (REAL_VALUE_ISNAN (r))
{
overflow = 1;
- high = 0;
- low = 0;
+ val = double_int_zero;
}
/* See if R is less than the lower bound or greater than the
@@ -2311,8 +2304,7 @@ fold_convert_const_int_from_real (enum tree_code code, tree type, const_tree arg
if (REAL_VALUES_LESS (r, l))
{
overflow = 1;
- high = TREE_INT_CST_HIGH (lt);
- low = TREE_INT_CST_LOW (lt);
+ val = tree_to_double_int (lt);
}
}
@@ -2325,16 +2317,15 @@ fold_convert_const_int_from_real (enum tree_code code, tree type, const_tree arg
if (REAL_VALUES_LESS (u, r))
{
overflow = 1;
- high = TREE_INT_CST_HIGH (ut);
- low = TREE_INT_CST_LOW (ut);
+ val = tree_to_double_int (ut);
}
}
}
if (! overflow)
- REAL_VALUE_TO_INT (&low, &high, r);
+ real_to_integer2 ((HOST_WIDE_INT *) &val.low, &val.high, &r);
- t = force_fit_type_double (type, low, high, -1,
+ t = force_fit_type_double (type, val.low, val.high, -1,
overflow | TREE_OVERFLOW (arg1));
return t;
}
@@ -2354,39 +2345,32 @@ fold_convert_const_int_from_fixed (tree type, const_tree arg1)
mode = TREE_FIXED_CST (arg1).mode;
if (GET_MODE_FBIT (mode) < 2 * HOST_BITS_PER_WIDE_INT)
{
- lshift_double (temp.low, temp.high,
- - GET_MODE_FBIT (mode), 2 * HOST_BITS_PER_WIDE_INT,
- &temp.low, &temp.high, SIGNED_FIXED_POINT_MODE_P (mode));
+ temp = double_int_rshift (temp, GET_MODE_FBIT (mode),
+ HOST_BITS_PER_DOUBLE_INT,
+ SIGNED_FIXED_POINT_MODE_P (mode));
/* Left shift temp to temp_trunc by fbit. */
- lshift_double (temp.low, temp.high,
- GET_MODE_FBIT (mode), 2 * HOST_BITS_PER_WIDE_INT,
- &temp_trunc.low, &temp_trunc.high,
- SIGNED_FIXED_POINT_MODE_P (mode));
+ temp_trunc = double_int_lshift (temp, GET_MODE_FBIT (mode),
+ HOST_BITS_PER_DOUBLE_INT,
+ SIGNED_FIXED_POINT_MODE_P (mode));
}
else
{
- temp.low = 0;
- temp.high = 0;
- temp_trunc.low = 0;
- temp_trunc.high = 0;
+ temp = double_int_zero;
+ temp_trunc = double_int_zero;
}
/* If FIXED_CST is negative, we need to round the value toward 0.
By checking if the fractional bits are not zero to add 1 to temp. */
- if (SIGNED_FIXED_POINT_MODE_P (mode) && temp_trunc.high < 0
+ if (SIGNED_FIXED_POINT_MODE_P (mode)
+ && double_int_negative_p (temp_trunc)
&& !double_int_equal_p (TREE_FIXED_CST (arg1).data, temp_trunc))
- {
- double_int one;
- one.low = 1;
- one.high = 0;
- temp = double_int_add (temp, one);
- }
+ temp = double_int_add (temp, double_int_one);
/* Given a fixed-point constant, make new constant with new type,
appropriately sign-extended or truncated. */
t = force_fit_type_double (type, temp.low, temp.high, -1,
- (temp.high < 0
+ (double_int_negative_p (temp)
&& (TYPE_UNSIGNED (type)
< TYPE_UNSIGNED (TREE_TYPE (arg1))))
| TREE_OVERFLOW (arg1));
diff --git a/gcc/tree.c b/gcc/tree.c
index 5da82069131..83f1237fd85 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -1221,32 +1221,18 @@ build_int_cst_wide (tree type, unsigned HOST_WIDE_INT low, HOST_WIDE_INT hi)
tree
build_low_bits_mask (tree type, unsigned bits)
{
- unsigned HOST_WIDE_INT low;
- HOST_WIDE_INT high;
- unsigned HOST_WIDE_INT all_ones = ~(unsigned HOST_WIDE_INT) 0;
+ double_int mask;
gcc_assert (bits <= TYPE_PRECISION (type));
if (bits == TYPE_PRECISION (type)
&& !TYPE_UNSIGNED (type))
- {
- /* Sign extended all-ones mask. */
- low = all_ones;
- high = -1;
- }
- else if (bits <= HOST_BITS_PER_WIDE_INT)
- {
- low = all_ones >> (HOST_BITS_PER_WIDE_INT - bits);
- high = 0;
- }
+ /* Sign extended all-ones mask. */
+ mask = double_int_minus_one;
else
- {
- bits -= HOST_BITS_PER_WIDE_INT;
- low = all_ones;
- high = all_ones >> (HOST_BITS_PER_WIDE_INT - bits);
- }
+ mask = double_int_mask (bits);
- return build_int_cst_wide (type, low, high);
+ return build_int_cst_wide (type, mask.low, mask.high);
}
/* Checks that X is integer constant that can be expressed in (unsigned)
diff --git a/gcc/tree.h b/gcc/tree.h
index 1c7c3b3ca41..e30981ef0dd 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4841,10 +4841,10 @@ extern int mul_double_with_sign (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
mul_double_with_sign (l1, h1, l2, h2, lv, hv, false)
extern void lshift_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
HOST_WIDE_INT, unsigned int,
- unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, int);
+ unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, bool);
extern void rshift_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
HOST_WIDE_INT, unsigned int,
- unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, int);
+ unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, bool);
extern void lrotate_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
HOST_WIDE_INT, unsigned int,
unsigned HOST_WIDE_INT *, HOST_WIDE_INT *);