This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH]Fix computation of offset in ivopt
- From: "Bin.Cheng" <amker dot cheng at gmail dot com>
- To: Richard Biener <richard dot guenther at gmail dot com>
- Cc: "bin.cheng" <bin dot cheng at arm dot com>, GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 21 Oct 2013 05:01:31 +0800
- Subject: Re: [PATCH]Fix computation of offset in ivopt
- Authentication-results: sourceware.org; auth=none
- References: <001501ceb906$56da1c00$048e5400$ at arm dot com> <CAFiYyc0WO3M8x-0eyN4xpami9yemcX0cVy=awfOFYYmeo+OSyg at mail dot gmail dot com> <002701cebb3f$6fcd6ab0$4f684010$ at arm dot com> <CAFiYyc0M_7mSxED5YK7WYy+7mxd3Axdzdy=smnSEQj2iPx9m3A at mail dot gmail dot com> <002901cebd9f$5f7cb0a0$1e7611e0$ at arm dot com> <CAFiYyc1J1FBhsgsj9hgcMWg4o8M7soY3h4CGQWa+FyVqrEv_eQ at mail dot gmail dot com> <CAHFci295kKk7CXiEPfEGiPDy+ekew7TgEWygr-_prYbV9Sscow at mail dot gmail dot com> <CAFiYyc1r030B6H_XLt4iiLSabiCxWqN34BmQrcX+ZCfTtpMxpA at mail dot gmail dot com> <002e01cecafd$03809c60$0a81d520$ at arm dot com> <CAFiYyc34mD6Rx+JUmv8d=1UH3_eqgqoeLE7wE-qBX7XAye7+ow at mail dot gmail dot com>
On Fri, Oct 18, 2013 at 7:18 PM, Richard Biener
<richard.guenther@gmail.com> wrote:
> On Thu, Oct 17, 2013 at 7:52 AM, bin.cheng <bin.cheng@arm.com> wrote:
>> 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.
>
> 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);
>
> this is not correct - it will mishandle all large unsigned numbers.
As far as the patch itself. I think the preceding host_integerp
already checks for this case:
int
host_integerp (const_tree t, int pos)
{
if (t == NULL_TREE)
return 0;
return (TREE_CODE (t) == INTEGER_CST
&& ((TREE_INT_CST_HIGH (t) == 0
&& (HOST_WIDE_INT) TREE_INT_CST_LOW (t) >= 0)
|| (! pos && TREE_INT_CST_HIGH (t) == -1
&& (HOST_WIDE_INT) TREE_INT_CST_LOW (t) < 0
&& !TYPE_UNSIGNED (TREE_TYPE (t)))
|| (pos && TREE_INT_CST_HIGH (t) == 0)));
}
Since the call is host_integerp (xxx, 0), it returns 0 for large
unsigned numbers, right?
>
> The real issue is that we rely on twos-complement arithmetic to work
> when operating on pointer offsets (because we convert them all to
> unsigned sizetype). That makes interpreting the offsets or expressions
> that compute offsets hard (or impossible in some cases), as you can
> see from the issues in IVOPTs.
>
> The above means that strip_offset_1 cannot reliably look through
> MULT_EXPRs as that can make an offset X * CST that is
> "effectively" signed "surely" unsigned in the process. Think of
> this looking into X * CST as performing a division - whose result
> is dependent on the sign of X which we lost with our unsigned
> casting. Now, removing the MULT_EXPR look-through might
> be too pessimizing ... but it may be worth trying to see if it fixes
> your issue? In this context I also remember a new bug filed
> recently of us not folding x /[ex] 4 * 4 to x.
>
> In the past I was working multiple times on stopping doing that
> (make all offsets unsigned), but I never managed to finish ...
>
> Richard.
>
>> Bootstrap and test on x86/x86_64/arm. Is it OK?
>>
>> Thanks.
>> bin
>>
>> Patch a:
>> 2013-10-17 Bin Cheng <bin.cheng@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.cheng@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.cheng@arm.com>
>>
>> * gcc.dg/tree-ssa/ivopts-outside-loop-use-1.c: New test.
>>
>>> -----Original Message-----
>>> From: Richard Biener [mailto:richard.guenther@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.cheng@gmail.com> wrote:
>>> > On Tue, Oct 1, 2013 at 6:50 PM, Richard Biener
>>> > <richard.guenther@gmail.com> wrote:
>>> >> On Mon, Sep 30, 2013 at 7:39 AM, bin.cheng <bin.cheng@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
--
Best Regards.