My main discomfort is the double-int part. At this point in time the only usage of double-int left on the branch is because the fixed ints use it as their underlying representation. I think that rather than doing a lot of work to accommodate this, it would be better to just change the fixed representation.

There is no place for exactly two HWIs in the machine independent parts of the compiler, and the truth is that there is no (except for the fixed stuff) use of double ints remaining in the ports. Even if, by sniffing the ports, we end up with a flavor of wide-int that has two wide-ints as its rep, it should not be be called double-int or expose what it's rep is.

I do understand that richi had requested this in some of the early discussions but given that there are virtually no clients for it left, lets let this die.

As for the rest of the patch, this is for the c++ experts to hash out. I have no problems with it but i am not an expert and so if the consensus likes it, then we can go in this direction.

==== small bugs below this line.
bottom of frag 3 of gcc/cp/init.c is wrong: you replaced rshift...lshift with lshift...lshift.

i will finish reading this tomorrow, but i wanted to get some comments in for the early shift. i stopped reading at line 1275.

kenny

On 09/01/2013 03:21 PM, Richard Sandiford wrote:
This is an RFC and patch for an alternative way of organising the
wide-int classes, along the lines I mentioned earlier.  The main points
are below, each with a "headline" and a bit of extra waffle that can be
skipped if too long:

* As Richard requested, the main wide int class is parameterised by the
   storage:

     template <typename storage>
     class GTY(()) generic_wide_int : public storage

* As Richard also requested, double_int is now implemented in terms of
   the wide-int routines.

   This didn't work out quite as elegantly as I'd hoped due to conflicting
   requirements.  double_int is used in unions and so needs to be a POD,
   whereas the fancy things we want to allow for wide_int and fixed_wide_int
   mean that they need to have constructors.  The patch therefore keeps
   double_int as the basic storage class and defines double_int_ext as
   the wide-int class.  All the double_int methods therefore need to be
   kept, but are now simple wrappers around the wi:: routines.

   double_int_ext and fixed_wide_int <HOST_BITS_PER_DOUBLE_INT> are
   assignment-compatible.

   This is just to show that it's possible though.  It probably isn't
   very efficient...

* wide-int.h no longer includes tree.h, rtl.h or double-int.h.

   The rtx and machine_mode routines are now in rtl.h, and the
   tree-related ones are in tree.h.  double-int.h now depends on
   wide-int.h, as described above.

* wide-int.h no longer includes tm.h.

   This is done by adding a new MAX_BITS_PER_UNIT to machmode.def,
   so that the definition of MAX_BITSIZE_MODE_ANY_MODE no longer relies on
   BITS_PER_UNIT.  Although I think we usually assume that BITS_PER_UNIT
   is a constant, that wouldn't necessarily be true if we ever did support
   multi-target compilers in future.  MAX_BITS_PER_UNIT is logically
   the maximum value of BITS_PER_UNIT for any compiled-in target and must
   be a constant.

* Precision 0 is no longer a special marker for primitive types like ints.
   It's only used for genuine 0-width integers.

* The wide-int classes are now relatively light-weight.  All the real
   work is done by wi:: routines.

   There are still operator methods for addition, multiplication, etc.,
   but they just forward to the associated wi:: routine.  I also reluctantly
   kept and_not and or_not as operator-like methods for now, although I'd
   like to get rid of them and just keep the genuine operators.  The problem
   is that I'd have liked the AND routine to be "wi::and", but of course that
   isn't possible with "and" being a keyword, so I went for "wi::bit_and"
   instead.  Same for "not" and "wi::bit_not", and "or" and "wi::bit_or".
   Then it seemed like the others should be bit_* too, and "wi::bit_and_not"
   just seems a bit unwieldly...

   Hmm, if we decide to forbid the use of "and" in gcc, perhaps we could
   #define it to something safe.  But that would probably be too confusing.
   I'm sure those who like stepping through gcc with gdb are going to hate
   this patch already, without that to make things worse...

* fixed_wide_int <N> now only has the number of HWIs required by N.
   This makes addr_wide_int significantly smaller.

* fixed_wide_int <N> doesn't have a precision field; the precision
   is always taken directly from the template argument.

   This isn't a win sizewise, since the length and precision fitted snugly
   into a HWI slot, but it means that checks for particular precisions
   can be resolved at compile time.  E.g. the fast single-HWI paths are
   now dropped when dealing with fixed_wide_ints.

* Each integer type is classifed as one of: FLEXIBLE_PRECISION,
   CONST_PRECISION and VAR_PRECISION.

   FLEXIBLE_PRECISION is for integers with both a precision and a signedness,
   like trees and C "int"s.  In the case of C types like "int", the precision
   depends on the host.

   CONST_PRECISION is for integers with a constant precision and no signedness,
   like fixed_wide_int and double_int.  (OK, I realise saying that double_int
   has no signedness is controversial...)
The problem with double int is that it was only signed if the precision going in was strictly less that 128 bits. Every pass that used it either had to special case TImode or just say that i do not care if the answer was wrong. And the middle end was about 50/50 as to which way a pass was written.



   VAR_PRECISION is for integers with a variable precision and no signedness,
   like wide_int and rtx constants.

* It is possible to operate directly on two non-wide-int objects.
   E.g. wi::add (tree_val, 1) is allowed, as is wi::add (rtx_pair_t (...), 1),
   wi::sub (0, wide_int_val) and wi::lshift (10, 64).

   The rules are the symmetric extension of:

     FLEXIBLE_PRECISION op FLEXIBLE_PRECISION => max_wide_int
     FLEXIBLE_PRECISION op CONST_PRECISION (N) => fixed_wide_int <N>
     FLEXIBLE_PRECISION op VAR_PRECISION => wide_int
     CONST_PRECISION (N) op CONST_PRECISION (N) => fixed_wide_int <N>
     VAR_PRECISION op VAR_PRECISION => wide_int

   which probably sounds complicated, but I think is pretty natural
   in practice.  Mixtures between CONST_PRECISION and VAR_PRECISION
   seem dangerous and so fail to compile.  Mixtures between different
   CONST_PRECISION widths make no sense and so again fail to compile.

   There are a couple of extra rules for double_int to get around
   the PODness thing above.   Although double_int_ext and
   fixed_wide_int <HOST_BITS_PER_DOUBLE_INT> are assignment-compatible,
   a plain double_int cannot be initialised from a fixed_wide_int due
   to the lack of double_int contructors.  See the binary_traits in
   double-int.h for details.

* A static assert in the constructor prevents wide_ints from being
   initialised from types with host-dependent precision (such as "int").

* A static assert also prevents fixed_wide_ints from being initialised
   from wide_ints.  I think combinations like that would always be a
   mistake.

I've deliberately not tackled any of the other things that have been
talked about, such as whether excess bits should be defined, whether
the blocks should be HWIs, etc.  I've also kept things like
"wi::one (prec)", although this is now exactly equivalent to
"wi::shwi (1, prec)".  I'm not sure either way on whether the
one() form is worth keeping.

The patch is in three parts.  The first is the new wide-int.h,
which is the one I'm really asking about.  The second has the changes
to double-int.h and double-int.c.  The third contains all the other
changes, including those to wide-int.cc.

The third part in particular might need some clean-up, but like I say
I'm really asking about the first part for now.  The entire patch did
pass bootstrap & regression test on x86_64-linux-gnu though.
(Admittedly with a bit of hackery.  The new versions of build_int_cst*
trigger an RA bug in which debug insns affect the chosen allocation.
That isn't caused by a bug in the wide-int patches themselves, since I
can reproduce it with the same testcase on mainline.  I'll try to look
into it when I get time, but for now I've added an
__attribute__((optimize(0))) to the affected routines.)

The big block comment at the top of wide-int.h probably also needs
tweaking after these changes.

Thoughts?

Richard


Reply via email to