On Wed, Oct 31, 2012 at 1:05 PM, Richard Sandiford <rdsandif...@googlemail.com> wrote: > Richard Biener <richard.guent...@gmail.com> writes: >> On Wed, Oct 31, 2012 at 11:43 AM, Richard Sandiford >> <rdsandif...@googlemail.com> wrote: >>> Richard Biener <richard.guent...@gmail.com> writes: >>>> On Thu, Oct 25, 2012 at 12:55 PM, Kenneth Zadeck >>>> <zad...@naturalbridge.com> wrote: >>>>> >>>>> On 10/25/2012 06:42 AM, Richard Biener wrote: >>>>>> >>>>>> On Wed, Oct 24, 2012 at 7:23 PM, Mike Stump <mikest...@comcast.net> >>>>>> wrote: >>>>>>> >>>>>>> On Oct 24, 2012, at 2:43 AM, Richard Biener <richard.guent...@gmail.com> >>>>>>> wrote: >>>>>>>> >>>>>>>> On Tue, Oct 23, 2012 at 6:12 PM, Kenneth Zadeck >>>>>>>> <zad...@naturalbridge.com> wrote: >>>>>>>>> >>>>>>>>> On 10/23/2012 10:12 AM, Richard Biener wrote: >>>>>>>>>> >>>>>>>>>> + HOST_WIDE_INT val[2 * MAX_BITSIZE_MODE_ANY_INT / >>>>>>>>>> HOST_BITS_PER_WIDE_INT]; >>>>>>>>>> >>>>>>>>>> are we sure this rounds properly? Consider a port with max byte mode >>>>>>>>>> size 4 on a 64bit host. >>>>>>>>> >>>>>>>>> I do not believe that this can happen. The core compiler includes >>>>>>>>> all >>>>>>>>> modes up to TI mode, so by default we already up to 128 bits. >>>>>>>> >>>>>>>> And mode bitsizes are always power-of-two? I suppose so. >>>>>>> >>>>>>> Actually, no, they are not. Partial int modes can have bit sizes that >>>>>>> are not power of two, and, if there isn't an int mode that is bigger, >>>>>>> we'd >>>>>>> want to round up the partial int bit size. Something like ((2 * >>>>>>> MAX_BITSIZE_MODE_ANY_INT + HOST_BITS_PER_WIDE_INT - 1) / >>>>>>> HOST_BITS_PER_WIDE_INT should do it. >>>>>>> >>>>>>>>>> I still would like to have the ability to provide specializations of >>>>>>>>>> wide_int >>>>>>>>>> for "small" sizes, thus ideally wide_int would be a template >>>>>>>>>> templated >>>>>>>>>> on the number of HWIs in val. Interface-wise wide_int<2> should be >>>>>>>>>> identical to double_int, thus we should be able to do >>>>>>>>>> >>>>>>>>>> typedef wide_int<2> double_int; >>>>>>>>> >>>>>>>>> If you want to go down this path after the patches get in, go for it. >>>>>>>>> I >>>>>>>>> see no use at all for this. >>>>>>>>> This was not meant to be a plug in replacement for double int. This >>>>>>>>> goal of >>>>>>>>> this patch is to get the compiler to do the constant math the way that >>>>>>>>> the >>>>>>>>> target does it. Any such instantiation is by definition placing some >>>>>>>>> predefined limit that some target may not want. >>>>>>>> >>>>>>>> Well, what I don't really like is that we now have two implementations >>>>>>>> of functions that perform integer math on two-HWI sized integers. What >>>>>>>> I also don't like too much is that we have two different interfaces to >>>>>>>> operate >>>>>>>> on them! Can't you see how I come to not liking this? Especially the >>>>>>>> latter … >>>>>>> >>>>>>> double_int is logically dead. Reactoring wide-int and double-int is a >>>>>>> waste of time, as the time is better spent removing double-int from the >>>>>>> compiler. All the necessary semantics and code of double-int _has_ been >>>>>>> refactored into wide-int already. Changing wide-int in any way to vend >>>>>>> anything to double-int is wrong, as once double-int is removed, >>>>>>> then all the >>>>>>> api changes to make double-int share from wide-int is wasted and must >>>>>>> then >>>>>>> be removed. The path forward is the complete removal of double-int; it >>>>>>> is >>>>>>> wrong, has been wrong and always will be wrong, nothing can change that. >>>>>> >>>>>> double_int, compared to wide_int, is fast and lean. I doubt we will >>>>>> get rid of it - you >>>>>> will make compile-time math a _lot_ slower. Just profile when you for >>>>>> example >>>>>> change get_inner_reference to use wide_ints. >>>>>> >>>>>> To be able to remove double_int in favor of wide_int requires _at least_ >>>>>> templating wide_int on 'len' and providing specializations for 1 and 2. >>>>>> >>>>>> It might be a non-issue for math that operates on trees or RTXen due to >>>>>> the allocation overhead we pay, but in recent years we transitioned >>>>>> important >>>>>> paths away from using tree math to using double_ints _for speed reasons_. >>>>>> >>>>>> Richard. >>>>> >>>>> i do not know why you believe this about the speed. double int always >>>>> does synthetic math since you do everything at 128 bit precision. >>>>> >>>>> the thing about wide int, is that since it does math to the precision's >>>>> size, it almost never does uses synthetic operations since the sizes for >>>>> almost every instance can be done using the native math on the machine. >>>>> almost every call has a check to see if the operation can be done >>>>> natively. >>>>> I seriously doubt that you are going to do TI mode math much faster than i >>>>> do it and if you do who cares. >>>>> >>>>> the number of calls does not effect the performance in any negative way >>>>> and >>>>> it fact is more efficient since common things that require more than one >>>>> operation in double in are typically done in a single operation. >>>> >>>> Simple double-int operations like >>>> >>>> inline double_int >>>> double_int::and_not (double_int b) const >>>> { >>>> double_int result; >>>> result.low = low & ~b.low; >>>> result.high = high & ~b.high; >>>> return result; >>>> } >>>> >>>> are always going to be faster than conditionally executing only one >>>> operation >>>> (but inside an offline function). >>> >>> OK, this is really in reply to the 4.8 thing, but it felt more >>> appropriate here. >>> >>> It's interesting that you gave this example, since before you were >>> complaining about too many fused ops. Clearly this one could be >>> removed in favour of separate and() and not() operations, but why >>> not provide a fused one if there are clients who'll make use of it? >> >> I was more concerned about fused operations that use precision >> or bitsize as input. That is for example >> >>>> + bool only_sign_bit_p (unsigned int prec) const; >>>> + bool only_sign_bit_p () const; >> >> The first is construct a wide-int with precision prec (and sign- or >> zero-extend it) and then call only_sign_bit_p on it. Such function >> should not be necessary and existing callers should be questioned >> instead of introducing it. >> >> In fact wide-int seems to have so many "fused" operations that >> we run out of sensible recognizable names for them. Which results >> in a lot of confusion on what the functions actually do (at least for me). > > Well, I suppose I can't really say anything useful either way on > that one, since I'm not writing the patch and I'm not reviewing it :-) > >>> I think Kenny's API is just taking that to its logical conclusion. >>> There doesn't seem to be anything sacrosanct about the current choice >>> of what's fused and what isn't. >> >> Maybe. I'd rather have seen an initial small wide-int API and fused >> operations introduced separately together with the places they are >> used. In the current way it's way too tedious to go over all of them >> and match them with callers, lookup enough context and then >> make up my mind on whether the caller should do sth different or not. >> >> Thus, consider the big initial API a reason that all this review takes >> so long ... >> >>> The speed problem we had using trees for internal arithmetic isn't >>> IMO a good argument for keeping double_int in preference to wide_int. >>> Allocating and constructing tree objects to hold temporary values, >>> storing an integer representation in it, then calling tree arithmetic >>> routines that pull out the integer representation again and create a >>> tree to hold the result, is going to be much slower than using either >>> double_int or wide_int. I'd be very surprised if we notice any >>> measurable difference between double_int and wide_int here. >>> >>> I still see no reason to keep double_int around. The width of a host >>> wide integer really shouldn't have any significance. >>> >>> Your main complaint seems to be that the wide_int API is different >>> from the double_int one, but we can't literally use the same API, since >>> double_int has an implicit precision and bitsize, and wide_int doesn't. >>> Having a precision that is separate from the underlying representation >>> is IMO the most important feature of wide_int, so: >>> >>> template wide_int<2> double_int; >>> >>> is never going to be a drop-in, API-compatible replacement for double_int. >> >> My reasoning was that if you strip wide-int of precision and bitsize >> you have a double_int<N> class. > > But you don't! Because... > >> Thus wide-int should have a base >> of that kind and just add precision / bitsize ontop of that. It wouldn't >> be a step forward if we end up replacing double_int uses with >> wide_int uses with precision of 2 * HOST_BITS_PER_WIDE_INT, >> would it? > > ...the precision and bitsize isn't an optional extra, either conceptually > or in implementation. wide_int happens to use N HOST_WIDE_INTS under > the hood, but the value of N is an internal implementation detail. > No operations are done to N HWIs, they're done to the number of bits > in the operands. Whereas a double_int<N> class does everything to N HWIs.
If that's the only effect then either bitsize or precision is redundant (and we also have len ...). Note I did not mention len above, thus the base class would retain 'len' and double-int would simply use 2 for it (if you don't template it but make it variable). Richard. > Richard