On Fri, Oct 5, 2012 at 6:34 PM, Kenneth Zadeck <zad...@naturalbridge.com> 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 >> <richard.guent...@gmail.com> 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.