On Fri, Oct 5, 2012 at 6:34 PM, Kenneth Zadeck <[email protected]> wrote:
> richard s,
> there are two comments that i deferred to you. that have the word richard
> in them,
>
> richi,
> thank, i will start doing this now.
>
> kenny
>
> On 10/05/2012 09:49 AM, Richard Guenther wrote:
>>
>> On Fri, Oct 5, 2012 at 2:39 PM, Richard Guenther
>> <[email protected]> wrote:
>>>
>>> Ok, I see where you are going. Let me look at the patch again.
>>
>> * The introduction and use of CONST_SCALAR_INT_P could be split out
>> (obvious and good)
>>
>> * DEF_RTL_EXPR(CONST_WIDE_INT, "const_wide_int", "", RTX_CONST_OBJ)
>> defining that new RTX is orthogonal to providing the wide_int
>> abstraction
>> for operating on CONST_INT and CONST_DOUBLE, right?
>>
>> @@ -144,6 +144,7 @@ static bool
>> prefer_and_bit_test (enum machine_mode mode, int bitnum)
>> {
>> bool speed_p;
>> + wide_int mask = wide_int::set_bit_in_zero (bitnum, mode);
>>
>> set_bit_in_zero ... why use this instead of
>> wide_int::zero (mode).set_bit (bitnum) that would match the old
>> double_int_zero.set_bit interface and be more composed of primitives?
>
> adding something like this was just based on usage. We do this operation
> all over the place, why not make it concise and efficient. The api is
> very bottom up. I looked at what the clients were doing all over the place
> and added those functions.
>
> wide-int has both and_not and or_not. double-int only has and_not, but
> there are a lot of places in where you do or_nots, so we have or_not also.
>
>
>> if (and_test == 0)
>> {
>> @@ -164,8 +165,7 @@ prefer_and_bit_test (enum machine_mode m
>> }
>>
>> /* Fill in the integers. */
>> - XEXP (and_test, 1)
>> - = immed_double_int_const (double_int_zero.set_bit (bitnum), mode);
>> + XEXP (and_test, 1) = immed_wide_int_const (mask);
>>
>> I suppose immed_wide_int_const may create a CONST_INT, a CONST_DOUBLE
>> or a CONST_WIDE_INT?
>
> yes, on converted targets it builds const_ints and const_wide_ints and on
> unconverted targets it builds const_ints and const_doubles. The reason i
> did not want to convert the targets is that the code that lives in the
> targets generally wants to use the values to create constants and this code
> is very very very target specific.
>
>>
>> +#if TARGET_SUPPORTS_WIDE_INT
>> +/* Returns 1 if OP is an operand that is a CONST_INT or CONST_WIDE_INT.
>> */
>> +int
>> +const_scalar_int_operand (rtx op, enum machine_mode mode)
>> +{
>>
>> why is it necessary to condition anything on TARGET_SUPPORTS_WIDE_INT?
>> It seems testing/compile coverage of this code will be bad ...
>>
>> Can't you simply map CONST_WIDE_INT to CONST_DOUBLE for targets
>
> The accessors for the two are completely different. const doubles "know"
> that there are exactly two hwi's. for const_wide_ints, you only know that
> the len is greater than 1. anything with len 1 would be CONST_INT.
>
> In a modern c++ world, const_int would be a subtype of const_int, but that
> is a huge patch.
>
>
>> not supporting CONST_WIDE_INT (what does it mean to "support"
>> CONST_WIDE_INT? Does a target that supports CONST_WIDE_INT no
>> longer use CONST_DOUBLEs for integers?)
>
> yes, that is exactly what it means.
>
>> + if (!CONST_WIDE_INT_P (op))
>> + return 0;
>>
>> hm, that doesn't match the comment (CONST_INT is supposed to return 1 as
>> well).
>> The comment doesn't really tell what the function does it seems,
>
> I need some context here to reply.
>
>
>> + int prec = GET_MODE_PRECISION (mode);
>> + int bitsize = GET_MODE_BITSIZE (mode);
>> +
>> + if (CONST_WIDE_INT_NUNITS (op) * HOST_BITS_PER_WIDE_INT > bitsize)
>> + return 0;
>>
>> it's mode argument is not documented. And this doesn't even try to see if
>> the constant would fit the mode anyway (like if it's zero). Not sure what
>> the function is for.
>
> I will upgrade the comments, they were inherited from the old version with
> the const_double changed to the const_wide_int
>
>
>> + {
>> + /* Multiword partial int. */
>> + HOST_WIDE_INT x
>> + = CONST_WIDE_INT_ELT (op, CONST_WIDE_INT_NUNITS (op) - 1);
>> + return (wide_int::sext (x, prec & (HOST_BITS_PER_WIDE_INT - 1))
>> + == x);
>>
>> err - so now we have wide_int with a mode but we pass in another mode
>> and see if they have the same value? Same value as-in signed value?
>> Which probably is why you need to rule out different size constants above?
>> Because you don't know whether to sign or zero extend?
>
> no it is worse than that. I made the decision, which i think is correct,
> that we were not going to carry the mode inside const_wide_int. The
> justification was that we do not do it for const_int. There is a comment
> in the constructor for const_wide_int that says it would be so easy to just
> put this in.
>
> But, this is an old api that did not change. only the internals changed to
> support const_wide_int.
>
>
>>
>> +/* Returns 1 if OP is an operand that is a CONST_WIDE_INT. */
>> +int
>> +const_wide_int_operand (rtx op, enum machine_mode mode)
>> +{
>>
>> similar comments, common code should be factored out at least.
>> Instead of conditioning a whole set of new function on supports-wide-int
>> please add cases to the existing functions to avoid diverging in pieces
>> that both kind of targets support.
>
> in some places i do one and in some i do the other. it really just depends
> on how much common code there was. For these there was almost no common
> code.
>
>
>> @@ -2599,7 +2678,7 @@ constrain_operands (int strict)
>> break;
>>
>> case 'n':
>> - if (CONST_INT_P (op) || CONST_DOUBLE_AS_INT_P (op))
>> + if (CONST_SCALAR_INT_P (op))
>> win = 1;
>>
>> factoring out this changes would really make the patch less noisy.
>
> i will this weekend.
>
>> skipping to rtl.h bits
>>
>> +struct GTY((variable_size)) hwivec_def {
>> + int num_elem; /* number of elements */
>> + HOST_WIDE_INT elem[1];
>> +};
>>
>> num_elem seems redundant and computable from GET_MODE_SIZE.
>
> NOT AT ALL. CONST_WIDE_INT and TREE_INT_CST only have enough elements in
> the array to hold the actual value, they do not have enough elements to hold
> the mode or type.
> in real life almost all integer constants of any type are very small. in
> the rtl word, we almost never actually create any CONST_WIDE_INT outside of
> the test cases, because CONST_INT handles the cases, and i assume that at
> the tree level, almost every int cst will have an len of 1.
>
>
>
>> Or do you want to optimize encoding like for CONST_INT (and unlike
>> CONST_DOUBLE)? I doubt the above packs nicely into rtx_def?
>> A general issue of it though - we waste 32bits on 64bit hosts in
>> rtx_def between the bits and the union. Perfect place for num_elem
>> (if you really need it) and avoids another 4 byte hole. Similar issue
>> exists in rtvec_def.
>
> I am going to let richard answer this.
>
>
>> back to where I was
>>
>> @@ -645,6 +673,10 @@ iterative_hash_rtx (const_rtx x, hashval
>> return iterative_hash_object (i, hash);
>> case CONST_INT:
>> return iterative_hash_object (INTVAL (x), hash);
>> + case CONST_WIDE_INT:
>> + for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
>> + hash = iterative_hash_object (CONST_WIDE_INT_ELT (x, i), hash);
>> + return hash;
>>
>> I see CONST_DOUBLEs value is not hashed. Why hash wide-ints value?
>
> There are a lot of ugly things that one uncovers when one looks at code this
> old.
> the idea was to bring whatever i touched up to best practice standards.
>
>
>> Seeing
>>
>> +#define HWI_GET_NUM_ELEM(HWIVEC) ((HWIVEC)->num_elem)
>> +#define HWI_PUT_NUM_ELEM(HWIVEC, NUM) ((HWIVEC)->num_elem = (NUM))
>>
>> skipping to
>>
>> +#if TARGET_SUPPORTS_WIDE_INT
>> + {
>> + rtx value = const_wide_int_alloc (len);
>> + unsigned int i;
>> +
>> + /* It is so tempting to just put the mode in here. Must control
>> + myself ... */
>> + PUT_MODE (value, VOIDmode);
>> + HWI_PUT_NUM_ELEM (CONST_WIDE_INT_VEC (value), len);
>>
>> why is NUM_ELEM not set in const_wide_int_alloc, and only there?
>>
>> +extern rtx rtx_alloc_stat_v (RTX_CODE MEM_STAT_DECL, int);
>> +#define rtx_alloc_v(c, SZ) rtx_alloc_stat_v (c MEM_STAT_INFO, SZ)
>> +#define const_wide_int_alloc(NWORDS) \
>> + rtx_alloc_v (CONST_WIDE_INT, \
>> + (sizeof (struct hwivec_def) \
>> + + ((NWORDS)-1) * sizeof (HOST_WIDE_INT))) \
>>
>> because it's a macro(?). Ugh.
>>
>> I see CONST_DOUBLE for ints and CONST_WIDE_INT for ints use
>> is mutually exclusive. Good. What's the issue with converting targets?
>> Just retain the existing 2 * HWI limit by default.
>
> I have answered this elsewhere, the constant generation code on some
> platforms is tricky and i felt that would require knowledge of the port that
> i did not have. it is not just a bunch of c code, it is also changing
> patterns in the md files.
>
>
>> +#if TARGET_SUPPORTS_WIDE_INT
>> +
>> +/* Match CONST_*s that can represent compile-time constant integers. */
>> +#define CASE_CONST_SCALAR_INT \
>> + case CONST_INT: \
>> + case CONST_WIDE_INT
>> +
>>
>> I regard this abstraction is mostly because the transition is not
>> finished.
>> Not sure if seeing CASE_CONST_SCALAR_INT, CASE_CONST_UNIQUE (?),
>> CASE_CONST_ANY adds more to the confusion than spelling out all of them.
>> Isn't there sth like a tree-code-class for RTXen? That would catch
>> CASE_CONST_ANY, no?
>
> however, those abstractions are already in the trunk. They were put in
> earlier to make this patch smaller.
>
>> @@ -3081,6 +3081,8 @@ commutative_operand_precedence (rtx op)
>> /* Constants always come the second operand. Prefer "nice" constants.
>> */
>> if (code == CONST_INT)
>> return -8;
>> + if (code == CONST_WIDE_INT)
>> + return -8;
>> if (code == CONST_DOUBLE)
>> return -7;
>> if (code == CONST_FIXED)
>>
>> I think it should be the same as CONST_DOUBLE which it "replaces".
>> Likewise below, that avoids code generation changes (which there should
>> be none for a target that is converted, right?).
>
> not clear because it does not really replace const double - remember that
> const double still holds fp stuff. another one for richard to comment on.
>
>> @@ -5351,6 +5355,20 @@ split_double (rtx value, rtx *first, rtx
>> }
>> }
>> }
>> + else if (GET_CODE (value) == CONST_WIDE_INT)
>> + {
>> + gcc_assert (CONST_WIDE_INT_NUNITS (value) == 2);
>> + if (WORDS_BIG_ENDIAN)
>> + {
>> + *first = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
>> + *second = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
>> + }
>> + else
>> + {
>> + *first = GEN_INT (CONST_WIDE_INT_ELT (value, 0));
>> + *second = GEN_INT (CONST_WIDE_INT_ELT (value, 1));
>> + }
>> + }
>>
>> scary ;)
>
> unbelievably scary. This is one of those places where i really do not
> know what the code is doing and so i just put in something that was
> minimally correct. when we get some code where the assert hits then i
> will figure it out.
>
>
>> Index: gcc/sched-vis.c
>> ===================================================================
>> --- gcc/sched-vis.c (revision 191978)
>> +++ gcc/sched-vis.c (working copy)
>> @@ -444,14 +444,31 @@ print_value (char *buf, const_rtx x, int
>> ...
>> case CONST_DOUBLE:
>> - if (FLOAT_MODE_P (GET_MODE (x)))
>> - real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0,
>> 1);
>> - else
>> + if (TARGET_SUPPORTS_WIDE_INT == 0 && !FLOAT_MODE_P (GET_MODE (x)))
>> sprintf (t,
>> "<" HOST_WIDE_INT_PRINT_HEX "," HOST_WIDE_INT_PRINT_HEX
>> ">",
>> (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x),
>> (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x));
>> + else
>> + real_to_decimal (t, CONST_DOUBLE_REAL_VALUE (x), sizeof (t), 0,
>> 1);
>> cur = safe_concat (buf, cur, t);
>> break;
>>
>> I don't see that this hunk is needed? In fact it's more confusing this
>> way.
>
> you are likely right. this is really there to say that this code would go
> away if
> (when) all targets support wide int, but i will get rid of it.
>
>> +/* If the target supports integers that are wider than two
>> + HOST_WIDE_INTs on the host compiler, then the target should define
>> + TARGET_SUPPORTS_WIDE_INT and make the appropriate fixups.
>> + Otherwise the compiler really is not robust. */
>> +#ifndef TARGET_SUPPORTS_WIDE_INT
>> +#define TARGET_SUPPORTS_WIDE_INT 0
>> +#endif
>>
>> I wonder what are the appropriate fixups?
>
> it was in the mail of the original patch. i will in the next round,
> transfer a cleaned up version of that into the doc for this target hook.
>
>>
>> -/* Return a CONST_INT or CONST_DOUBLE corresponding to target reading
>> - GET_MODE_BITSIZE (MODE) bits from string constant STR. */
>> +/* Return a CONST_INT, CONST_WIDE_INT, or CONST_DOUBLE corresponding
>> + to target reading GET_MODE_BITSIZE (MODE) bits from string constant
>> + STR. */
>>
>> maybe being less specific in this kind of comments and just refering to
>> RTX integer constants would be better?
>
> will do, i have done some like that.
>
>> ... skip ...
>>
>> Index: gcc/hwint.c
>> ===================================================================
>> --- gcc/hwint.c (revision 191978)
>> +++ gcc/hwint.c (working copy)
>> @@ -112,6 +112,29 @@ ffs_hwi (unsigned HOST_WIDE_INT x)
>> int
>> popcount_hwi (unsigned HOST_WIDE_INT x)
>> {
>> + /* Compute the popcount of a HWI using the algorithm from
>> + Hacker's Delight. */
>> +#if HOST_BITS_PER_WIDE_INT == 32
>>
>> separate patch please. With a rationale.
>
> fine.
>
>> ...
>>
>> +/* 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. */
>> +
>> +tree
>> +wide_int_to_tree (tree type, const wide_int &cst)
>> +{
>> + wide_int v;
>> + if (TYPE_UNSIGNED (type))
>> + v = cst.zext (TYPE_PRECISION (type));
>> + else
>> + v = cst.sext (TYPE_PRECISION (type));
>> +
>> + return build_int_cst_wide (type, v.elt (0), v.elt (1));
>>
>> this needs an assert that the wide-int contains two HWIs.
>
> as i said in an earlier mail, this is just transition code for when the tree
> level code goes in.
> but i see your point and will add the assert.
>
>
>
>> +#ifndef GENERATOR_FILE
>> +extern tree wide_int_to_tree (tree type, const wide_int &cst);
>> +#endif
>>
>> why's that? The header inclusion isn't guarded that way.
>
> there was a problem building without it. but i will look into it.
>
>> Stopping here, skipping to wide-int.[ch]
>>
>> +#define DEBUG_WIDE_INT
>> +#ifdef DEBUG_WIDE_INT
>> + /* Debugging routines. */
>> + static void debug_vw (const char* name, int r, const wide_int& o0);
>> + static void debug_vwh (const char* name, int r, const wide_int &o0,
>> + HOST_WIDE_INT o1);
>>
>> there is DEBUG_FUNCTION.
>>
>> +/* This is the maximal size of the buffer needed for dump. */
>> +const int MAX = (MAX_BITSIZE_MODE_ANY_INT / 4
>> + + MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT +
>> 32);
>>
>> I'd prefer a target macro for this, not anything based off
>> MAX_BITSIZE_MODE_ANY_INT just to allow no-op transition of a
>> target to wide-ints (which IMHO should be the default for all targets,
>> simplifying the patch).
>>
>> +wide_int
>> +wide_int::from_uhwi (unsigned HOST_WIDE_INT op0, enum machine_mode
>> mode, bool *overflow)
>> +{
>> ...
>> +#ifdef DEBUG_WIDE_INT
>> + if (dump_file)
>> + {
>> + char buf0[MAX];
>> + fprintf (dump_file, "%s: %s = " HOST_WIDE_INT_PRINT_HEX "\n",
>> + "wide_int::from_uhwi", result.dump (buf0), op0);
>> + }
>> +#endif
>>
>> hm, ok ... I suppose the debug stuff (which looks very noisy) is going to
>> be
>> removed before this gets committed anywhere?
>
> it is very noisy and i was just planning to turn it off. but it is very
> useful when there is a problem so i was not planning to actually remove it
> immediately.
>
>
>>
>> +wide_int
>> +wide_int::from_int_cst (const_tree tcst)
>> +{
>> +#if 1
>> + wide_int result;
>> + tree type = TREE_TYPE (tcst);
>>
>> should just call wide_it::from_double_int (tree_to_double_int (tcst))
>>
>> As I said elsewhere I don't think only allowing precisions that are
>> somewhere
>> in any mode is good enough. We need the actual precision here
>> (everywhere).
>
> i think that the case has been made that what wide int needs to store inside
> it is the precision and bitsize and that passing in the mode/tree type is
> just a convenience. I will make this change. Then we can have exposed
> constructors that just take bitsize and precision.
>
>
>
>> Index: gcc/wide-int.h
>> ===================================================================
>> --- gcc/wide-int.h (revision 0)
>> +++ gcc/wide-int.h (revision 0)
>> @@ -0,0 +1,718 @@
>> +/* Operations with very long integers.
>> + Copyright (C) 2012 Free Software Foundation, Inc.
>> ...
>> +
>> +#ifndef GENERATOR_FILE
>> +#include "hwint.h"
>> +#include "options.h"
>> +#include "tm.h"
>> +#include "insn-modes.h"
>> +#include "machmode.h"
>> +#include "double-int.h"
>> +#include <gmp.h>
>> +#include "insn-modes.h"
>>
>> ugh. Compare this with double-int.h which just needs <gmp.h> (and even
>> that
>> is a red herring) ...
>>
>> +#define wide_int_minus_one(MODE) (wide_int::from_shwi (-1, MODE))
>> +#define wide_int_zero(MODE) (wide_int::from_shwi (0, MODE))
>> +#define wide_int_one(MODE) (wide_int::from_shwi (1, MODE))
>> +#define wide_int_two(MODE) (wide_int::from_shwi (2, MODE))
>> +#define wide_int_ten(MODE) (wide_int::from_shwi (10, MODE))
>>
>> add static functions like
>>
>> wide_int wide_int::zero (MODE)
>
> ok
>
>> +class wide_int {
>> + /* Internal representation. */
>> + HOST_WIDE_INT val[MAX_BITSIZE_MODE_ANY_INT / HOST_BITS_PER_WIDE_INT];
>> + unsigned short len;
>> + enum machine_mode mode;
>>
>> you really need to store the precision here, not the mode. We do not have
>> a distinct mode for each of the tree constant precisions we see. So what
>> might work for RTL will later fail on trees, so better do it correct
>> from the start
>> (overloads using mode rather than precision may be acceptable - similarly
>> I'd consider overloads for tree types).
>
> discussed above.
>
>> len seems redundant unless you want to optimize encoding.
>> len == (precision + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT.
>
> that is exactly what we do. However, we are optimizing time, not space.
> the value is always stored in compressed form, i.e the same representation
> as is used inside the CONST_WIDE_INTs and INT_CSTs. this makes the
> transformation between them very fast. And since we do this a lot, it
> needs to be fast. So the len is the number of HWIs needed to represent the
> value which is typically less than what would be implied by the precision.
But doesn't this require a sign? Otherwise how do you encode TImode 0xffffffff?
Would len be 1 here? (and talking about CONST_WIDE_INT vs CONST_INT,
wouldn't CONST_INT be used anyway for all ints we can encode "small"? Or
is it (hopefully) the goal to replace CONST_INT with CONST_WIDE_INT
everywhere?) Or do you say wide_int is always "signed', thus TImode 0xffffffff
needs len == 2 and an explicit zero upper HWI word? Or do you say wide_int
is always "unsigned", thus TImode -1 needs len == 2? Noting that double-ints
were supposed to be twos-complement (thus, 'unsigned') numbers having
implicit non-zero bits sounds error-prone.
That said - I don't see any value in optimizing storage for short-lived
(as you say) wide-ints (apart from limiting it to the mode size). For
example mutating operations on wide-ints are not really possible
if you need to extend storage.
>> + enum Op {
>> + NONE,
>>
>> we don't have sth like this in double-int.h, why was the double-int
>> mechanism
>> not viable?
>
> i have chosen to use enums for things rather than passing booleans.
But it's bad to use an enum with 4 values for a thing that can only possibly
expect two. You cannot optimize tests as easily. Please retain the bool uns
parameters instead.
Richard.