Hi,
As noted in previous messages, GCC forces offset to unsigned in middle end.
It also gets offset value and stores it in HOST_WIDE_INT then uses it in
various computation.  In this scenario, It should use int_cst_value to do
additional sign extension against the type of tree node, otherwise we might
lose sign information.  Take function fold_plusminus_mult_expr as an
example, the sign information of arg01/arg11 might be lost because it uses
TREE_INT_CST_LOW directly.  I think this is the offender of the problem in
this thread.  I think we should fix the offender, rather the hacking
strip_offset as in the original patch, so I split original patch into two as
attached, with one fixing the offset of COMPONENT_REF in strip_offset_1, the
other fixing the mentioned sign extension problem.

Bootstrap and test on x86/x86_64/arm.  Is it OK?

Thanks.
bin

Patch a:
2013-10-17  Bin Cheng  <bin.ch...@arm.com>

        * tree-ssa-loop-ivopts.c (strip_offset_1): Change parameter type.
        Count DECL_FIELD_BIT_OFFSET when computing offset for COMPONENT_REF.

Patch b: 
2013-10-17  Bin Cheng  <bin.ch...@arm.com>

        * fold-const.c (fold_plusminus_mult_expr): Use int_cst_value instead
        of TREE_INT_CST_LOW.

gcc/testsuite/ChangeLog
2013-10-17  Bin Cheng  <bin.ch...@arm.com>

        * gcc.dg/tree-ssa/ivopts-outside-loop-use-1.c: New test.

> -----Original Message-----
> From: Richard Biener [mailto:richard.guent...@gmail.com]
> Sent: Wednesday, October 02, 2013 4:32 PM
> To: Bin.Cheng
> Cc: Bin Cheng; GCC Patches
> Subject: Re: [PATCH]Fix computation of offset in ivopt
> 
> On Tue, Oct 1, 2013 at 6:13 PM, Bin.Cheng <amker.ch...@gmail.com> wrote:
> > On Tue, Oct 1, 2013 at 6:50 PM, Richard Biener
> > <richard.guent...@gmail.com> wrote:
> >> On Mon, Sep 30, 2013 at 7:39 AM, bin.cheng <bin.ch...@arm.com>
> wrote:
> >>>
> >>>
> >>
> >> I don't think you need
> >>
> >> +  /* Sign extend off if expr is in type which has lower precision
> >> +     than HOST_WIDE_INT.  */
> >> +  if (TYPE_PRECISION (TREE_TYPE (expr)) <= HOST_BITS_PER_WIDE_INT)
> >> +    off = sext_hwi (off, TYPE_PRECISION (TREE_TYPE (expr)));
> >>
> >> at least it would be suspicious if you did ...
> > There is a problem for example of the first message.  The iv base if
like:
> > pretmp_184 + ((sizetype) KeyIndex_180 + 1073741823) * 4 I am not sure
> > why but it seems (-4/0xFFFFFFFC) is represented by (1073741823*4).
> > For each operand strip_offset_1 returns exactly the positive number
> > and result of multiplication never get its chance of sign extend.
> > That's why the sign extend is necessary to fix the problem. Or it
> > should be fixed elsewhere by representing iv base with:
> > "pretmp_184 + ((sizetype) KeyIndex_180 + 4294967295) * 4" in the first
> place.
> 
> Yeah, that's why I said the whole issue with forcing all offsets to be
unsigned
> is a mess ...
> 
> There is really no good answer besides not doing that I fear.
> 
> Yes, in the above case we could fold the whole thing differently
(interpret
> the offset of a POINTER_PLUS_EXPR as signed).  You can try tracking down
> the offender, but it'll get non-trivial easily as you have to consider the
fact
> that GCC will treat signed operations as having undefined behavior on
> overflow.
> 
> So I see why you want to do the extension above (re-interpret the result),
I
> suppose we can live with it but please make sure to add a big fat ???
> comment before it explaining why it is necessary.
> 
> Richard.
> 
> >>
> >> The only case that I can think of points to a bug in strip_offset_1
> >> again, namely if sizetype (the type of all offsets) is smaller than a
> >> HOST_WIDE_INT in which case
> >>
> >> +    boffset = int_cst_value (DECL_FIELD_BIT_OFFSET (field));
> >> +    *offset = off0 + int_cst_value (tmp) + boffset / BITS_PER_UNIT;
> >>
> >> is wrong as boffset / BITS_PER_UNIT does not do a signed division
> >> then (for negative boffset which AFAIK does not happen - but it would
> >> be technically allowed).  Thus, the predicates like
> >>
> >> +    && cst_and_fits_in_hwi (tmp)
> >>
> >> would need to be amended with a check that the MSB is not set.
> > So I can handle it like:
> >
> > +    abs_boffset = abs_hwi (boffset);
> > +    xxxxx = abs_boffset / BITS_PER_UNIT;
> > +    if (boffset < 0)
> > +      xxxxx = -xxxxx;
> > +    *offset = off0 + int_cst_value (tmp) + xxxxx;
> >
> > Right?
> >
> >>
> >> Btw, the cst_and_fits_in_hwi implementation is odd:
> >>
> >> bool
> >> cst_and_fits_in_hwi (const_tree x)
> >> {
> >>   if (TREE_CODE (x) != INTEGER_CST)
> >>     return false;
> >>
> >>   if (TYPE_PRECISION (TREE_TYPE (x)) > HOST_BITS_PER_WIDE_INT)
> >>     return false;
> >>
> >>   return (TREE_INT_CST_HIGH (x) == 0
> >>           || TREE_INT_CST_HIGH (x) == -1); }
> >>
> >> the precision check seems totally pointless and I wonder what's the
> >> point of this routine as there is host_integerp () already and
> >> tree_low_cst instead of int_cst_value - oh, I see, the latter
> >> forcefully sign-extends .... that should make the extension not
> >> necessary.
> > See above.
> >
> > Thanks.
> > bin
Index: gcc/tree-ssa-loop-ivopts.c
===================================================================
--- gcc/tree-ssa-loop-ivopts.c  (revision 203267)
+++ gcc/tree-ssa-loop-ivopts.c  (working copy)
@@ -2037,12 +2037,12 @@ find_interesting_uses (struct ivopts_data *data)
 
 static tree
 strip_offset_1 (tree expr, bool inside_addr, bool top_compref,
-               unsigned HOST_WIDE_INT *offset)
+               HOST_WIDE_INT *offset)
 {
   tree op0 = NULL_TREE, op1 = NULL_TREE, tmp, step;
   enum tree_code code;
   tree type, orig_type = TREE_TYPE (expr);
-  unsigned HOST_WIDE_INT off0, off1, st;
+  HOST_WIDE_INT off0, off1, st;
   tree orig_expr = expr;
 
   STRIP_NOPS (expr);
@@ -2133,19 +2133,32 @@ strip_offset_1 (tree expr, bool inside_addr, bool
       break;
 
     case COMPONENT_REF:
-      if (!inside_addr)
-       return orig_expr;
+      {
+       tree field;
 
-      tmp = component_ref_field_offset (expr);
-      if (top_compref
-         && cst_and_fits_in_hwi (tmp))
-       {
-         /* Strip the component reference completely.  */
-         op0 = TREE_OPERAND (expr, 0);
-         op0 = strip_offset_1 (op0, inside_addr, top_compref, &off0);
-         *offset = off0 + int_cst_value (tmp);
-         return op0;
-       }
+       if (!inside_addr)
+         return orig_expr;
+
+       tmp = component_ref_field_offset (expr);
+       field = TREE_OPERAND (expr, 1);
+       if (top_compref
+           && cst_and_fits_in_hwi (tmp)
+           && cst_and_fits_in_hwi (DECL_FIELD_BIT_OFFSET (field)))
+         {
+           HOST_WIDE_INT boffset, abs_off;
+
+           /* Strip the component reference completely.  */
+           op0 = TREE_OPERAND (expr, 0);
+           op0 = strip_offset_1 (op0, inside_addr, top_compref, &off0);
+           boffset = int_cst_value (DECL_FIELD_BIT_OFFSET (field));
+           abs_off = abs_hwi (boffset) / BITS_PER_UNIT;
+           if (boffset < 0)
+             abs_off = -abs_off;
+
+           *offset = off0 + int_cst_value (tmp) + abs_off;
+           return op0;
+         }
+      }
       break;
 
     case ADDR_EXPR:
@@ -2196,7 +2209,10 @@ strip_offset_1 (tree expr, bool inside_addr, bool
 static tree
 strip_offset (tree expr, unsigned HOST_WIDE_INT *offset)
 {
-  return strip_offset_1 (expr, false, false, offset);
+  HOST_WIDE_INT off;
+  tree core = strip_offset_1 (expr, false, false, &off);
+  *offset = off;
+  return core;
 }
 
 /* Returns variant of TYPE that can be used as base for different uses.
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c    (revision 203267)
+++ gcc/fold-const.c    (working copy)
@@ -7270,8 +7270,8 @@ fold_plusminus_mult_expr (location_t loc, enum tre
       HOST_WIDE_INT int01, int11, tmp;
       bool swap = false;
       tree maybe_same;
-      int01 = TREE_INT_CST_LOW (arg01);
-      int11 = TREE_INT_CST_LOW (arg11);
+      int01 = int_cst_value (arg01);
+      int11 = int_cst_value (arg11);
 
       /* Move min of absolute values to int11.  */
       if (absu_hwi (int01) < absu_hwi (int11))
Index: gcc/testsuite/gcc.dg/fold-pointer_plus_expr-offset.c
===================================================================
--- gcc/testsuite/gcc.dg/fold-pointer_plus_expr-offset.c        (revision 0)
+++ gcc/testsuite/gcc.dg/fold-pointer_plus_expr-offset.c        (revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-gimple" } */
+
+int foo(int *a, int l)
+{
+  while (l && ! a[l-1])
+    --l;
+
+  return l;
+}
+
+/* { dg-final { scan-tree-dump-not "1073741823" "gimple" } } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */

Reply via email to