On Fri, Oct 5, 2012 at 11:55 AM, Richard Sandiford
<rdsandif...@googlemail.com> wrote:
> Richard Guenther <richard.guent...@gmail.com> writes:
>>> As far as the wide_ints recording a mode or precision goes: we're in
>>> the "lucky" position of having tried both options.  Trees record the
>>> type (and thus precision) of all compile-time integer constants.
>>> RTL doesn't.  And the RTL way is a right pain.  It leads to interfaces
>>> in which rtx arguments often have to be accompanied by a mode.  And it
>>> leads to clunky differences like those between simplify_unary_operation
>>> (which takes two mode arguments) and simplify_binary_operation
>>> (which with our current set of binary operations requires only one).
>>
>> But the issue here is not that double_int doesn't record a mode
>> or precision (or a sign).  The issue is that CONST_DOUBLE and CONST_INT
>> don't!  The _tree_ INTEGER_CST contains of a type and a double-int.
>> I see double-int (and the proposed wide-int) as a common building-block
>> used for kind of "arbitrary precision" (as far as the target needs) integer
>> constants on both tree and RTL.  And having a common worker implementation
>> requires it to operate on something different than tree types or RTL mode
>> plus signedness.
>>
>>> To put it another way: every wide_int operation needs to know
>>> the precision of its arguments and the precision of its result.
>>
>> That's not true.  Every tree or RTL operation does, not every
>> wide_int operation.  double_int's are just twos-complement numbers
>> of precision 2 * HOST_BITS_PER_WIDE_INT.  wide_int's should
>> be just twos-complement numbers of precision len *
>> WHATEVER_HOST_COMPONENT_TYPE_IS_SUITABLE_FOR_A_FAST_IMPLEMENTATION.
>> Operations on double_int and wide_int are bare-metal,
>> in nearly all of the times you should use routines that do
>> proper sign-/zero-extending to a possibly smaller precision.  When
>> using bare-metal you are supposed to do that yourself.
>>
>> Which is why I was suggesting to add double_sint, double_uint,
>> double_sintp (with precision), etc., wrappers and operations.
>>
>>> Not storing the precision in the wide_int is putting the onus
>>> on the caller to keep track of the precision separately.
>>
>> But that's a matter of providing something high-level ontop of
>> the bare-metal double-int/wide-int (something shared between
>> RTL and trees).  Duplicating information in the bare-metal
>> doesn't make sense (and no, INTEGER_CSTs on the tree level
>> are _not_ short-lived, and how can a double-int make sense on
>> the tree level when you say it doesn't make sense on the RTL level?)
>
> I think we're talking at cross purposes here.  To the extent that
> I'm not really sure where to begin. :-)  Just in case this is it:
> the idea is that wide_int is the type used to _process_ integers.
> It is not suppoed to be the type used to store integers in the IRs.
> The way trees store integers and the way that RTL stores integers
> are up to them.  For RTL the idea is that we continue to store integers
> that happen to fit into a HWI as a CONST_INT (regardless of the size of
> the CONST_INT's context-determined mode).  Wider integers are stored
> as a CONST_DOUBLE (for unconverted targets) or a CONST_WIDE_INT
> (for converted targets).  None of the three use the wide_int type;
> they use more compact representations instead.  And as Kenny says,
> using CONST_INT continues to be an important way of reducing the
> IR footprint.
>
> Whenever we want to do something interesting with the integers,
> we construct a wide_int for them and use the same processing code
> for all three rtx types.  This avoids having the separate single-HWI
> and double-HWI paths that we have now.  It also copes naturally with
> cases where we start out with single-HWI values but end up with wider
> ones.
>
> But the operations that we do on these wide_ints will all be to a mode
> or precision.  Shifts of QImode integers are different from shifts of
> HImode integers, etc.
>
> If you knew all that already (you probably did) and I've completely
> missed the point, please say so. :-)
>
> I'm not sure what you mean by "bare metal".

The issue is that unlike RTL where we "construct" double-ints from
CONST_INT/CONST_DOUBLE right now, tree has the double-int
_embedded_.  That's why I say that the thing we embed in
a CONST_WIDE_INT or a tree INTEGER_CST needs to be
"bare metal", and that's what I would call wide-int.

I think you have two things mixed in this patch which might add to
the confusion (heh).  One is, making the thing you work on in RTL
(which used to be double-ints before this patch) be wide-ints
which carry additional information taken from the IL RTX piece
at construction time.  That's all nice and good.  The other thing
is adding a CONST_WIDE_INT to support wider integer constants
than the weird host-dependent limitation we have right now.
Mixing those things together probably made you be able to make
Kenny work on it ... heh ;)

So to me wide-ints provide the higher-level abstraction ontop of
double-ints (which would remain the storage entity).  Such
higher-level abstraction is very useful, also for double-ints and
also on the tree level.  There is no requirement to provide bigger
double-int (or wide-int) for this.  Let's call this abstraction
wide-int (as opposed to my suggested more piecemail double_sint,
double_uint).  You can perfectly model it ontop of the existing
double_int storage.

As of providing larger "double-ints" - there is not much code left
(ok, quite an overstatement ;)) that relies on the implementation
detail of double-int containing exactly two HOST_WIDE_INTs.
The exact purpose of double-ints was to _hide_ this (previously
we only had routines like mul_double_with_sign which take
two HOST_WIDE_INT components).  Most code dealing with
the implementation detail is code interfacing with middle-end
routines that take a HOST_WIDE_INT argument (thus the
double_int_fits_hwi_p predicates) - even wide_int has to support
this kind of interfacing.

So, after introducing wide_int that just wraps double_int and
changing all user code (hopefully all, I guess mostly all), we'd
tackle the issue that the size of double_int's is host dependent.
A simple solution is to make it's size dependent on a target macro
(yes, macro ...), so on a 32bit HWI host targeting a 64bit 'HWI' target
you'd simply have four HWIs in the 'double-int' storage (and
arithmetic needs to be generalized to support this).

[The more complex solution makes double-int* just a pointer to the first
HWI, so it cannot be used without being "wrapped" in a wide-int
which implicitely would provide the number of HWIs pointed to
(yes, I think variable-sized wide-int storage is the ultimate way to go).]

So ... can you possibly split the patch in a way that just does the
first thing (provide the high-level wrapper and make use of it from RTL)?
I don't see the reason to have both CONST_DOUBLE and CONST_WIDE,
in fact they should be the same given choice one for the 2nd step.
And you can of course trivially construct a wide-int from a CONST_INT
as well (given it has a mode).

As of using a mode or precision in wide-int - for re-use on the tree level
you need a precision as not all precisions have a distinct mode.  As on
RTL you don't have a sign we probably don't want wide-ints to have a sign
but continue double-int-like to specify the sign as part of the operation
where it matters.

Richard.

> Richard

Reply via email to