On Fri, Jan 26, 2018 at 02:11:19PM +0100, Richard Biener wrote:
> >> POINTER_PLUS_EXPR offets are to be interpreted as signed (ptrdiff_t)
> >> so using uhwi and then performing an unsigned division is wrong code.
> >> See mem_ref_offset how to deal with this (ugh - poly-ints...).  Basically
> >> you have to force the thing to signed.  Like just use
> >>
> >>   HOST_WIDE_INT offset = TREE_INT_CST_LOW (op01);
> >
> > Does it really matter here though?  Any negative offsets there are UB, we
> > should punt on them rather than try to optimize them.
> > As we known op01 is unsigned, if we check that it fits into shwi_p, it means
> > it will be 0 to shwi max and then we can handle it in uhwi too.
> 
> Ah, of course.  Didn't look up enough context to see what this code
> does in the end ;)
> 
> >           /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
> >           if (VECTOR_TYPE_P (op00type)
> >               && (same_type_ignoring_top_level_qualifiers_p
> > -                (type, TREE_TYPE (op00type))))
> > +                (type, TREE_TYPE (op00type)))
> > +             && tree_fits_shwi_p (op01))
> 
> nevertheless this appearant "mismatch" deserves a comment (checking
> shwi and using uhwi).

So like this?

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2018-01-26  Marek Polacek  <pola...@redhat.com>
            Jakub Jelinek  <ja...@redhat.com>

        PR c++/83659
        * constexpr.c (cxx_fold_indirect_ref): Use unsigned HOST_WIDE_INT
        when computing offsets.  Verify first that tree_fits_shwi_p (op01).
        Formatting fix.

        * g++.dg/torture/pr83659.C: New test.

--- gcc/cp/constexpr.c.jj       2018-01-24 17:18:42.392392254 +0100
+++ gcc/cp/constexpr.c  2018-01-26 18:54:43.991828743 +0100
@@ -3070,7 +3070,8 @@ cxx_fold_indirect_ref (location_t loc, t
        {
          tree part_width = TYPE_SIZE (type);
          tree index = bitsize_int (0);
-         return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width, 
index);
+         return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width,
+                                 index);
        }
       /* Also handle conversion to an empty base class, which
         is represented with a NOP_EXPR.  */
@@ -3109,12 +3110,22 @@ cxx_fold_indirect_ref (location_t loc, t
 
          /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
          if (VECTOR_TYPE_P (op00type)
-             && (same_type_ignoring_top_level_qualifiers_p
-                 (type, TREE_TYPE (op00type))))
+             && same_type_ignoring_top_level_qualifiers_p
+                                               (type, TREE_TYPE (op00type))
+             /* POINTER_PLUS_EXPR second operand is sizetype, unsigned,
+                but we want to treat offsets with MSB set as negative.
+                For the code below negative offsets are invalid and
+                TYPE_SIZE of the element is something unsigned, so
+                check whether op01 fits into HOST_WIDE_INT, which implies
+                it is from 0 to INTTYPE_MAXIMUM (HOST_WIDE_INT), and
+                then just use tree_to_uhwi because we want to treat the
+                value as unsigned.  */
+             && tree_fits_shwi_p (op01))
            {
-             HOST_WIDE_INT offset = tree_to_shwi (op01);
+             unsigned HOST_WIDE_INT offset = tree_to_uhwi (op01);
              tree part_width = TYPE_SIZE (type);
-             unsigned HOST_WIDE_INT part_widthi = tree_to_shwi 
(part_width)/BITS_PER_UNIT;
+             unsigned HOST_WIDE_INT part_widthi
+               = tree_to_uhwi (part_width) / BITS_PER_UNIT;
              unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
              tree index = bitsize_int (indexi);
 
--- gcc/testsuite/g++.dg/torture/pr83659.C.jj   2018-01-26 18:46:40.077572013 
+0100
+++ gcc/testsuite/g++.dg/torture/pr83659.C      2018-01-26 18:56:36.822888606 
+0100
@@ -0,0 +1,18 @@
+// PR c++/83659
+// { dg-do compile }
+
+typedef int V __attribute__ ((__vector_size__ (16)));
+V a;
+V b[2];
+
+int
+foo ()
+{
+  return reinterpret_cast <int *> (&a)[-1] += 1;
+}
+
+int
+bar ()
+{
+  return reinterpret_cast <int *> (&a[1])[-1];
+}


        Jakub

Reply via email to