This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [wide-int] int_traits <tree>


On 10/17/2013 04:46 AM, Richard Biener wrote:
the case actually comes up on the ppc because they do a lot of 128 bit
math.    I think i got thru the x86-64 without noticing this.
Well, it'd be suspicious if we're directly using 128-bit numbers
in addr_wide_int.  The justification for the assertion was that we
should explicitly truncate to addr_wide_int when deliberately
ignoring upper bits, beyond bit or byte address width.  128 bits
definitely falls into that category on powerpc.
My question is whether with 8-bit HWI 0x00 0xff 0xff is a valid
wide-int value if it has precision 16.  AFAIK that is what the
code produces, but now Kenny says this is only for some kind
of wide-ints but not all?  That is, why is

The issue is not that the rules are different between the different flavors of wide int, it is that the circumstances are different. The rule is that the only bits above the precision that exist are if the precision is not an even multiple of the HBPWI. In that case, the bits are always an extension of the sign bits.

max_wide_int and addr_wide_int have large enough precisions so that it is impossible to ever generate an unsigned number on the target that is large enough to ever run against the precision. However, for the fixed precision case, you can, and at least on the ppc, you do, generate unsigned numbers that are big enough to have to be recanonicalized like this.

inline wi::storage_ref
wi::int_traits <const_tree>::decompose (HOST_WIDE_INT *scratch,
                                         unsigned int precision, const_tree
x)
{
   unsigned int len = TREE_INT_CST_NUNITS (x);
   const HOST_WIDE_INT *val = (const HOST_WIDE_INT *) &TREE_INT_CST_ELT (x,
0);
   return wi::storage_ref (val, len, precision);
}

not a valid implementation together with making sure that the
INTEGER_CST tree rep has that extra word of zeros if required?
I would like to see us move in that direction (given that the
tree rep of INTEGER_CST has transitioned to variable-length already).

Btw, code such as

tree
wide_int_to_tree (tree type, const wide_int_ref &pcst)
{
...
   unsigned int small_prec = prec & (HOST_BITS_PER_WIDE_INT - 1);
   bool recanonize = sgn == UNSIGNED
     && small_prec
     && (prec + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT ==
len;

definitely needs a comment.  I would have thought _all_ unsigned
numbers need re-canonicalization.  Well, maybe only if we're
forcing the extra zeros.
It will get a comment.
[This function shows another optimization issue:

     case BOOLEAN_TYPE:
       /* Cache false or true.  */
       limit = 2;
       if (wi::leu_p (cst, 1))
         ix = cst.to_uhwi ();

I would have expected cst <= 1 be optimized to cst.len == 1 &&
cst.val[0] <= 1.  It expands to

<L27>:
   MEM[(long int *)&D.50698 + 16B] = 1;
   MEM[(struct wide_int_ref_storage *)&D.50698] = &MEM[(struct
wide_int_ref_storage *)&D.50698].scratch;
   MEM[(struct wide_int_ref_storage *)&D.50698 + 8B] = 1;
   MEM[(struct wide_int_ref_storage *)&D.50698 + 12B] = 32;
   _277 = MEM[(const struct wide_int_storage *)&cst + 260B];
   if (_277 <= 64)
     goto <bb 42>;
   else
     goto <bb 43>;

   <bb 42>:
   xl_491 = zext_hwi (1, 32);  // ok, checking enabled and thus out-of-line
   _494 = MEM[(const long int *)&cst];
   _495 = (long unsigned int) _494;
   yl_496 = zext_hwi (_495, _277);
   _497 = xl_491 < yl_496;
   goto <bb 44>;

   <bb 43>:
   _503 = wi::ltu_p_large (&MEM[(struct wide_int_ref_storage
*)&D.50698].scratch, 1, 32, &MEM[(const struct wide_int_storage
*)&cst].val, len_274, _277);

this keeps D.50698 and cst un-SRAable - inline storage is problematic
for this reason.  But the representation should guarantee the
compare with a low precision (32 bit) constant is evaluatable
at compile-time if len of the larger value is > 1, no?

   <bb 44>:
   # _504 = PHI <_497(42), _503(43)>
   D.50698 ={v} {CLOBBER};
   if (_504 != 0)
     goto <bb 45>;
   else
     goto <bb 46>;

   <bb 45>:
   pretmp_563 = MEM[(const struct wide_int_storage *)&cst + 256B];
   goto <bb 229> (<L131>);

   <bb 46>:
   _65 = generic_wide_int<wide_int_storage>::to_uhwi (&cst, 0);
   ix_66 = (int) _65;
   goto <bb 91>;

The question is whether we should try to optimize wide-int for
such cases or simply not use wi:leu_p (cst, 1) but rather

  if (cst.fits_uhwi_p () == 1 && cst.to_uhwi () < 1)

?
i find this ugly, but i see where you are coming from. The problem is that both you and i know that the len has to be 1, but the optimizer does not. This is a case where I think that we made a mistake getting rid of the wi::one_p, wi::zero_p and wi::minus_one_p. The internals of one_p were return (len == 1 && val[0] ==1) and i think that is much nicer than what you put there. On the other hand, it seem that a person more skilled than i am with c++ could specialize the comparisons with an integer constant, since i believe that that constant must fit in one hwi (I am a little concerned about large unsigned constants).

Thanks,
Richard




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]