This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: patch to canonicalize tree-csts.
- From: Kenneth Zadeck <zadeck at naturalbridge dot com>
- To: Richard Biener <rguenther at suse dot de>, gcc-patches <gcc-patches at gcc dot gnu dot org>, Mike Stump <mikestump at comcast dot net>, rdsandiford at googlemail dot com
- Date: Fri, 04 Oct 2013 09:03:12 -0400
- Subject: Re: patch to canonicalize tree-csts.
- Authentication-results: sourceware.org; auth=none
- References: <5238B585 dot 2020703 at naturalbridge dot com> <alpine dot LNX dot 2 dot 00 dot 1309241539100 dot 29411 at zhemvz dot fhfr dot qr> <5241986B dot 7040306 at naturalbridge dot com> <alpine dot LNX dot 2 dot 00 dot 1309241550270 dot 29411 at zhemvz dot fhfr dot qr> <524D7A13 dot 6060303 at naturalbridge dot com> <871u42e8c7 dot fsf at sandifor-thinkpad dot stglab dot manchester dot uk dot ibm dot com> <524D8465 dot 8000301 at naturalbridge dot com> <87hacytjmm dot fsf at talisman dot default>
So here is a patch with the change. As before, bootstrapped an tested on
x86-64.
On 10/03/2013 12:16 PM, Richard Sandiford wrote:
Kenneth Zadeck <zadeck@naturalbridge.com> writes:
Changing the representation of unsigned constants is only worthwhile
if we can avoid the force_to_size for some unsigned cases. I think we can
avoid it for precision >= xprecision && !small_prec. Either we should take
the hit of doing that comparison (but see below) or the change isn't
worthwhile.
i think that it is something closer to precision >= xprecision +
HOST_BITS_PER_WIDE_INT && ...
The problem is that the tree cst may have one extra block beyond the
precision.
Ah, OK.
I was thinking that we should always be able to use the constant as-is
for max_wide_int-based and addr_wide_int-based operations. The small_prec
again, you can get edge cased to death here. i think it would work
for max because that really is bigger than anything else, but it is
possible (though unlikely) to have something big converted to an address
by truncation.
But I'd have expected that conversion to be represented by an explicit
CONVERT_EXPR or NOP_EXPR. It seems wrong to use addr_wide_int directly on
something that isn't bit- or byte-address-sized. It'd be the C equivalent
of int + long -> int rather than the expected int + long -> long.
Same goes for wide_int. If we're doing arithmetic at a specific
precision, it seems odd for one of the inputs to be wider and yet
not have an explicit truncation.
Thanks,
Richard
Index: gcc/tree.c
===================================================================
--- gcc/tree.c (revision 203039)
+++ gcc/tree.c (working copy)
@@ -1187,10 +1187,10 @@ wide_int_to_tree (tree type, const wide_
tree t;
int ix = -1;
int limit = 0;
- int i;
+ unsigned int i;
gcc_assert (type);
- int prec = TYPE_PRECISION (type);
+ unsigned int prec = TYPE_PRECISION (type);
signop sgn = TYPE_SIGN (type);
/* Verify that everything is canonical. */
@@ -1204,11 +1204,11 @@ wide_int_to_tree (tree type, const wide_
}
wide_int cst = wide_int::from (pcst, prec, sgn);
- int len = int (cst.get_len ());
- int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
+ unsigned int len = int (cst.get_len ());
+ unsigned int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
bool recanonize = sgn == UNSIGNED
- && (prec + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT == len
- && small_prec;
+ && small_prec
+ && (prec + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT == len;
switch (TREE_CODE (type))
{
@@ -1235,7 +1235,7 @@ wide_int_to_tree (tree type, const wide_
case INTEGER_TYPE:
case OFFSET_TYPE:
- if (TYPE_UNSIGNED (type))
+ if (TYPE_SIGN (type) == UNSIGNED)
{
/* Cache 0..N */
limit = INTEGER_SHARE_LIMIT;
@@ -1294,7 +1294,7 @@ wide_int_to_tree (tree type, const wide_
must be careful here because tree-csts and wide-ints are
not canonicalized in the same way. */
gcc_assert (TREE_TYPE (t) == type);
- gcc_assert (TREE_INT_CST_NUNITS (t) == len);
+ gcc_assert (TREE_INT_CST_NUNITS (t) == (int)len);
if (recanonize)
{
len--;
@@ -1321,7 +1321,10 @@ wide_int_to_tree (tree type, const wide_
TREE_VEC_ELT (TYPE_CACHED_VALUES (type), ix) = t;
}
}
- else if (cst.get_len () == 1)
+ else if (cst.get_len () == 1
+ && (TYPE_SIGN (type) == SIGNED
+ || recanonize
+ || cst.elt (0) >= 0))
{
/* 99.99% of all int csts will fit in a single HWI. Do that one
efficiently. */
@@ -1351,14 +1354,29 @@ wide_int_to_tree (tree type, const wide_
for the gc to take care of. There will not be enough of them
to worry about. */
void **slot;
- tree nt = make_int_cst (len);
- TREE_INT_CST_NUNITS (nt) = len;
+ tree nt;
+ if (!recanonize
+ && TYPE_SIGN (type) == UNSIGNED
+ && cst.elt (len - 1) < 0)
+ {
+ unsigned int blocks_needed
+ = (prec + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT;
+
+ nt = make_int_cst (blocks_needed + 1);
+ for (i = len; i < blocks_needed; i++)
+ TREE_INT_CST_ELT (nt, i) = (HOST_WIDE_INT)-1;
+
+ TREE_INT_CST_ELT (nt, blocks_needed) = 0;
+ }
+ else
+ nt = make_int_cst (len);
if (recanonize)
{
len--;
TREE_INT_CST_ELT (nt, len) = zext_hwi (cst.elt (len), small_prec);
}
- for (int i = 0; i < len; i++)
+
+ for (i = 0; i < len; i++)
TREE_INT_CST_ELT (nt, i) = cst.elt (i);
TREE_TYPE (nt) = type;
@@ -10556,7 +10574,8 @@ widest_int_cst_value (const_tree x)
#if HOST_BITS_PER_WIDEST_INT > HOST_BITS_PER_WIDE_INT
gcc_assert (HOST_BITS_PER_WIDEST_INT >= HOST_BITS_PER_DOUBLE_INT);
- gcc_assert (TREE_INT_CST_NUNITS (x) <= 2);
+ gcc_assert (TREE_INT_CST_NUNITS (x) <= 2
+ || (TREE_INT_CST_NUNITS (x) == 3 && TREE_INT_CST_ELT (x, 2) == 0));
if (TREE_INT_CST_NUNITS (x) == 1)
val = ((HOST_WIDEST_INT)val << HOST_BITS_PER_WIDE_INT) >> HOST_BITS_PER_WIDE_INT;
@@ -10565,7 +10584,8 @@ widest_int_cst_value (const_tree x)
<< HOST_BITS_PER_WIDE_INT);
#else
/* Make sure the sign-extended value will fit in a HOST_WIDE_INT. */
- gcc_assert (TREE_INT_CST_NUNITS (x) == 1);
+ gcc_assert (TREE_INT_CST_NUNITS (x) == 1
+ || (TREE_INT_CST_NUNITS (x) == 2 && TREE_INT_CST_ELT (x, 1) == 0));
#endif
if (bits < HOST_BITS_PER_WIDEST_INT)
Index: gcc/tree.h
===================================================================
--- gcc/tree.h (revision 203039)
+++ gcc/tree.h (working copy)
@@ -3050,7 +3050,8 @@ cst_fits_shwi_p (const_tree x)
if (TREE_CODE (x) != INTEGER_CST)
return false;
- return TREE_INT_CST_NUNITS (x) == 1;
+ return TREE_INT_CST_NUNITS (x) == 1
+ || (TREE_INT_CST_NUNITS (x) == 2 && TREE_INT_CST_ELT (x, 1) == 0);
}
/* Checks that X is integer constant that can be expressed in signed
@@ -3093,7 +3094,7 @@ tree_fits_uhwi_p (const_tree cst)
/* For numbers of unsigned type that are longer than a HWI, if
the top bit of the bottom word is set, and there is not
another element, then this is too large to fit in a single
- hwi. */
+ hwi. For signed numbers, negative values are not allowed. */
if (TREE_INT_CST_ELT (cst, 0) >= 0)
return true;
}
@@ -5172,39 +5173,46 @@ wi::int_traits <const_tree>::get_precisi
return TYPE_PRECISION (TREE_TYPE (tcst));
}
-/* Convert the tree_cst X into a wide_int. */
+/* Convert the tree_cst X into a wide_int of PRECISION. */
inline wi::storage_ref
wi::int_traits <const_tree>::decompose (HOST_WIDE_INT *scratch,
unsigned int precision, const_tree x)
{
- unsigned int xprecision = get_precision (x);
unsigned int len = TREE_INT_CST_NUNITS (x);
const HOST_WIDE_INT *val = (const HOST_WIDE_INT *) &TREE_INT_CST_ELT (x, 0);
unsigned int max_len = ((precision + HOST_BITS_PER_WIDE_INT - 1)
/ HOST_BITS_PER_WIDE_INT);
- /* Truncate the constant if necessary. */
- if (len > max_len)
- return wi::storage_ref (val, max_len, precision);
- if (precision <= xprecision)
+ /* Got to be careful of precision 0 values. */
+ if (precision)
+ len = MIN (len, max_len);
+ if (TYPE_SIGN (TREE_TYPE (x)) == UNSIGNED)
{
- if (precision < HOST_BITS_PER_WIDE_INT
- && TYPE_SIGN (TREE_TYPE (x)) == UNSIGNED)
+ unsigned int small_prec = precision & (HOST_BITS_PER_WIDE_INT - 1);
+ if (small_prec)
{
- /* The rep of wide-int is signed, so if the value comes from
- an unsigned int_cst, we have to sign extend it to make it
- correct. */
- scratch[0] = sext_hwi (val[0], precision);
- return wi::storage_ref (scratch, 1, precision);
+ /* We have to futz with this because the canonization for
+ short unsigned numbers in wide-int is different from the
+ canonized short unsigned numbers in the tree-cst. */
+ if (len == max_len)
+ {
+ for (unsigned int i = 0; i < len - 1; i++)
+ scratch[i] = val[i];
+ scratch[len - 1] = sext_hwi (val[len - 1], precision);
+ return wi::storage_ref (scratch, len, precision);
+ }
+ }
+
+ unsigned int xprecision = get_precision (x);
+ if (precision < xprecision + HOST_BITS_PER_WIDE_INT)
+ {
+ len = wi::force_to_size (scratch, val, len, xprecision, precision, UNSIGNED);
+ return wi::storage_ref (scratch, len, precision);
}
- /* Otherwise we can use the constant as-is when not extending. */
- return wi::storage_ref (val, len, precision);
}
- /* Widen the constant according to its sign. */
- len = wi::force_to_size (scratch, val, len, xprecision, precision,
- TYPE_SIGN (TREE_TYPE (x)));
- return wi::storage_ref (scratch, len, precision);
+ /* Signed and the rest of the unsigned cases are easy. */
+ return wi::storage_ref (val, len, precision);
}
namespace wi
Index: gcc/wide-int.cc
===================================================================
--- gcc/wide-int.cc (revision 203039)
+++ gcc/wide-int.cc (working copy)
@@ -342,9 +342,7 @@ wi::force_to_size (HOST_WIDE_INT *val, c
}
}
}
- else if (precision < xprecision)
- /* Contracting. */
- len = canonize (val, len, precision);
+ len = canonize (val, len, precision);
return len;
}