On Wed, Oct 3, 2012 at 7:15 PM, Kenneth Zadeck <zad...@naturalbridge.com> wrote:
> The enclosed patch is the third of at least four patches that fix the
> problems associated with supporting integers on the target that are
> wider than two HOST_WIDE_INTs.
>
> While GCC claims to support OI mode, and we have two public ports that
> make minor use of this mode, in practice, compilation that uses OImode
> mode commonly gives the wrong result or ices.  We have a private port
> of GCC for an architecture that is further down the road to needing
> comprehensive OImode and we have discovered that this is unusable. We
> have decided to fix it in a general way that so that it is most
> beneficial to the GCC community.  It is our belief that we are just a
> little ahead of the X86 and the NEON and these patches will shortly be
> essential.
>
> The first two of these patches were primarily lexigraphical and have
> already been committed.    They transformed the uses of CONST_DOUBLE
> so that it is easy to tell what the intended usage is.
>
> The underlying structures in the next two patches are very general:
> once they are added to the compiler, the compiler will be able to
> support targets with any size of integer from hosts of any size
> integer.
>
> The patch enclosed deals with the portable RTL parts of the compiler.
> The next patch, which is currently under construction deals with the
> tree level.  However, this patch can be put on the trunk as is, and it
> will eleviate many, but not all of the current limitations in the rtl
> parts of the compiler.
>
> Some of the patch is conditional, depending on a port defining the
> symbol 'TARGET_SUPPORTS_WIDE_INT' to be non zero.  Defining this
> symbol to be non zero is declaring that the port has been converted to
> use the new form or integer constants.  However, the patch is
> completely backwards compatible to allow ports that do not need this
> immediately to convert at their leasure.  The conversion process is
> not difficult, but it does require some knowledge of the port, so we
> are not volinteering to do this for all ports.
>
> OVERVIEW OF THE PATCH:
>
> The patch defines a new datatype, a 'wide_int' (defined in
> wide-int.[ch], and this datatype will be used to perform all of the
> integer constant math in the compiler.  Externally, wide-int is very
> similar to double-int except that it does not have the limitation that
> math must be done on exactly two HOST_WIDE_INTs.
>
> Internally, a wide_int is a structure that contains a fixed sized
> array of HOST_WIDE_INTs, a length field and a mode.  The size of the

That it has a mode sounds odd to me and makes it subtly different
from HOST_WIDE_INT and double-int.  Maybe the patch will tell
why this is so.

> array is determined at generation time by dividing the number of bits
> of the largest integer supported on the target by the number of bits
> in a HOST_WIDE_INT of the host.  Thus, with this format, any length of
> integer can be supported on any host.
>
> A new rtx type is created, the CONST_WIDE_INT, which contains a
> garbage collected array of HOST_WIDE_INTS that is large enough to hold
> the constant.  For the targets that define TARGET_SUPPORTS_WIDE_INT to
> be non zero, CONST_DOUBLES are only used to hold floating point
> values.  If the target leaves TARGET_SUPPORTS_WIDE_INT defined as 0,
> CONST_WIDE_INTs are not used and CONST_DOUBLEs are as they were
> before.
>
> CONST_INT does not change except that it is defined to hold all
> constants that fit in exactly one HOST_WIDE_INT.  Note that is slightly
> different than the current trunk.  Before this patch, the TImode
> constant '5' could either be in a CONST_INT or CONST_DOUBLE depending
> on which code path was used to create it.  This patch changes this so
> that if the constant fits in a CONST_INT then it is represented in a
> CONST_INT no matter how it is created.
>
> For the array inside a CONST_WIDE_INT, and internally in wide-int, we
> use a compressed form for integers that need more than one
> HOST_WIDE_INT.  Higher elements of the array are not needed if they
> are just a sign extension of the elements below them.  This does not
> imply that constants are signed or are sign extended, this is only a
> compression technique.
>
> While it might seem to be more esthetically pleasing to have not
> introduced the CONST_WIDE_INT and to have changed the representation
> of the CONST_INT to accomodate larger numbers, this would have both
> used more space and would be a time consuming change for the port
> maintainers.  We believe that most ports can be quickly converted with
> the current scheme because there is just not a lot of code in the back
> ends that cares about large constants.  Furthermore, the CONST_INT is
> very space efficient and even in a program that was heavy in large
> values, most constants would still fit in a CONST_INT.
>
> All of the parts of the rtl level that deal with CONST_DOUBLE as an
> now conditionally work with CONST_WIDE_INTs depending on the value
> of TARGET_SUPPORTS_WIDE_INT.  We believe that this patch removes all
> of the ices and wrong code places at the portable rtl level. However,
> there are still places in the portable rtl code that refuse to
> transform the code unless it is a CONST_INT.  Since these do not cause
> failures, they can be handled later.  The patch is already very large.
>
> It should be noted that much of the constant overflow checking in the
> constant math dissappears with these patches.  The overflow checking
> code in the current compiler is really divided into two cases:
> overflow on the host and overflow on the target.  The overflow
> checking on the host was to make sure that the math did overflow when
> done on two HOST_WIDE_INTs.  All of this code goes away.  These
> patches allow the constant math to be done exactly the way it is done
> on the target.
>
> This patch also aids other cleanups that are being considered at the
> rtl level:
>
>   1) These patches remove most of the host dependencies on the
>   optimizations.  Currently a 32 bit GCC host will produce different
>   code for a specific target than a 64 bit host will.  This is because
>   many of the transformations only work on constants that can be a
>   represented with a single HWI or two HWIs.  If the target has larger
>   integers than the host, the compilation suffers.
>
>   2) Bernd's need to make GCC correctly support partial its is made
>   easier by the wide-int library.  This library carefully does all
>   arithmetic in the precision of the mode included in it.  While there
>   are still places at the rtl level that still do arithmetic inline,
>   we plan to convert those to use the library over time.   This patch
>   converts a substantial number of those places.
>
>   3) This patch is one step along the path to add modes to rtl integer
>   constants.  There is no longer any checking to see if a CONST_DOUBLE
>   has VOIDmode as its mode.  Furthermore, all constructors for various
>   wide ints do take a mode and require that it not be VOIDmode. There
>   is still a lot of work to do to make this conversion possible.
>
> Richard Sandiford has been over the rtl portions of this patch a few
> times.  He has not looked at the wide-int files in any detail.  This
> patch has been heavily tested on my private ports and also on x86-64.
>
>
> CONVERSION PROCESS
>
> Converting a port mostly requires looking for the places where
> CONST_DOUBLES are used with VOIDmode and replacing that code with code
> that accesses CONST_WIDE_INTs.  "grep -i const_double" at the port
> level gets you to 95% of the changes that need to be made.  There are
> a few places that require a deeper look.
>
>   1) There is no equivalent to hval and lval for CONST_WIDE_INTs.
>   This would be difficult to express in the md language since there
>   are a variable number of elements.
>
>   Most ports only check that hval is either 0 or -1 to see if the int
>   is small.  As mentioned above, this will no longer be necessary
>   since small constants are always CONST_INT.  Of course there are
>   still a few exceptions, the alpha's constraint used by the zap
>   instruction certainly requires careful examination by C code.
>   However, all the current code does is pass the hval and lval to C
>   code, so evolving the c code to look at the CONST_WIDE_INT is not
>   really a large change.
>
>   2) Because there is no standard template that ports use to
>   materialize constants, there is likely to be some futzing that is
>   unique to each port in this code.
>
>   3) The rtx costs may have to be adjusted to properly account for
>   larger constants that are represented as CONST_WIDE_INT.
>
> All and all it has not taken us long to convert ports that we are
> familiar with.
>
> OTHER COMMENTS
>
> I did find what i believe is one interesting bug in the double-int
> code.  I believe that the code that performs divide and mod with round
> to nearest is seriously wrong for unsigned integers.  I believe that
> it will get the wrong answer for any numbers that are large enough to
> look negative if they consider signed integers.  Asside from that,
> wide-int should perform in a very similar manner to double-int.
>
> I am sorry for the size of this patch.   However, there does not appear
> to change the underlying data structure to support wider integers
> without doing something like this.

Some pieces can be easily split out, like the introduction and use
of CONST_SCALAR_INT_P.

As my general comment I would like to see double-int and wide-int
unified from an interface perspective.  Which means that double-int
should be a specialization of wide-int which should be a template
(which also means its size is constant).  Thus,

typedef wide_int<2> double_int;

should be the way to expose the double_int type.

The main question remains - why does wide_int have a mode?
That looks redundant, both with information stored in types
and the RTL constant, and with the len field (that would be
always GET_MODE_SIZE () / ...?).  Also when you associate
a mode it's weird you don't associate a signedness.

Thus I'd ask you to rework this to be a template on 'len'
(number of HOST_WIDE_INT words), drop the mode member
and unify double-int and wide-int.  Co-incidentially incrementally
doing this by converting double-int to a typedef of a
wide_int<2> specialization (thus moving double-int implementation
stuff to be wide_int<2> specialized) would be prefered.

Btw,

+/* 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));
+}

is surely broken.  A wide-int does not fit a double-int.  How are you
going to "fix" this?

Thanks,
Richard.

> kenny

Reply via email to