On 23/05/16 15:06, Richard Biener wrote:
On Mon, May 23, 2016 at 3:19 PM, Kyrill Tkachov
<kyrylo.tkac...@foss.arm.com> wrote:
On 23/05/16 13:46, Richard Biener wrote:
n Mon, May 23, 2016 at 2:28 PM, Kyrill Tkachov
<kyrylo.tkac...@foss.arm.com> wrote:
On 23/05/16 12:27, Richard Biener wrote:
On Mon, May 23, 2016 at 1:17 PM, Kyrill Tkachov
<kyrylo.tkac...@foss.arm.com> wrote:
Hi all,
In this PR we end up hitting a signed overflow in
noce_get_alt_condition
when we try to
increment or decrement a HOST_WIDE_INT that might be HOST_WIDE_INT_MAX
or
HOST_WIDE_INT_MIN.
I've confirmed the overflow by adding an assert before the operation:
gcc_assert (desired_val != HOST_WIDE_INT_MAX);
This patch fixes those cases by catching the cases when desired_val has
the
extreme
value and avoids the transformation that function is trying to make.
Bootstrapped and tested on arm, aarch64, x86_64.
I've added the testcase that I used to trigger the assert mentioned
above
as
a compile test,
though I'm not sure how much value it has...
Ok for trunk?
If this isn't also a wrong-code issue (runtime testcase?) then why not
perform
the operation in unsigned HOST_WIDE_INT instead?
This part of the code transforms a comparison "x < CST" to "x <= CST - 1"
and similar transformations. Fro what I understand the LT,LE,GT,GE RTL
comparison
operators operate on signed integers, so I'm not sure how valid it would
be
to do all this on unsigned HOST_WIDE_INT.
But then this is a wrong-code issue and you should see miscompiles
and thus can add a dg-do run testcase instead?
I couldn't get it to miscompile anything, because the check:
"actual_val == desired_val + 1" where desired_val + 1 has signed
overflow doesn't return true, so the transformation doesn't happen anyway.
I think whether a miscompilation can occur depends on whether the compiler
used
to compile GCC itself does anything funky with the undefined behaviour
that's
occurring, which is why we should fix it. I suppose the testcase in this
patch only
goes so far to show that GCC doesn't crash, but not much else. I can make it
an execute
testcase if you'd like, but I can't get it to fail on my setup (the
generated assembly
looks correct on inspection).
Please make it a execute testcase anyway.
Ok with that change.
Thanks Richard, here it is with the testcase made executable.
Committing to trunk.
Kyrill
2016-05-25 Kyrylo Tkachov <kyrylo.tkac...@arm.com>
PR rtl-optimization/66940
* ifcvt.c (noce_get_alt_condition): Check that incrementing or
decrementing desired_val will not overflow before performing these
operations.
2016-05-25 Kyrylo Tkachov <kyrylo.tkac...@arm.com>
PR rtl-optimization/66940
* gcc.c-torture/execute/pr66940.c: New test.
Thanks,
Richard.
Kyrill
Kyrill
Richard.
Thanks,
Kyrill
Richard.
Thanks,
Kyrill
2016-05-23 Kyrylo Tkachov <kyrylo.tkac...@arm.com>
PR rtl-optimization/66940
* ifcvt.c (noce_get_alt_condition): Check that incrementing or
decrementing desired_val will not overflow before performing
these
operations.
2016-05-23 Kyrylo Tkachov <kyrylo.tkac...@arm.com>
PR rtl-optimization/66940
* gcc.c-torture/compile/pr66940.c: New test.
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 6ce51ba70464ce8ec79e217d290c2ab14f317651..cab054889aea7fafab7b5310da45ef7b3fc7e50b 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -2416,28 +2416,32 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
switch (code)
{
case LT:
- if (actual_val == desired_val + 1)
+ if (desired_val != HOST_WIDE_INT_MAX
+ && actual_val == desired_val + 1)
{
code = LE;
op_b = GEN_INT (desired_val);
}
break;
case LE:
- if (actual_val == desired_val - 1)
+ if (desired_val != HOST_WIDE_INT_MIN
+ && actual_val == desired_val - 1)
{
code = LT;
op_b = GEN_INT (desired_val);
}
break;
case GT:
- if (actual_val == desired_val - 1)
+ if (desired_val != HOST_WIDE_INT_MIN
+ && actual_val == desired_val - 1)
{
code = GE;
op_b = GEN_INT (desired_val);
}
break;
case GE:
- if (actual_val == desired_val + 1)
+ if (desired_val != HOST_WIDE_INT_MAX
+ && actual_val == desired_val + 1)
{
code = GT;
op_b = GEN_INT (desired_val);
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr66940.c b/gcc/testsuite/gcc.c-torture/execute/pr66940.c
new file mode 100644
index 0000000000000000000000000000000000000000..fbd109dccc72c290d935d81a3f3dd219f11f908d
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr66940.c
@@ -0,0 +1,20 @@
+long long __attribute__ ((noinline, noclone))
+foo (long long ival)
+{
+ if (ival <= 0)
+ return -0x7fffffffffffffffL - 1;
+
+ return 0x7fffffffffffffffL;
+}
+
+int
+main (void)
+{
+ if (foo (-1) != (-0x7fffffffffffffffL - 1))
+ __builtin_abort ();
+
+ if (foo (1) != 0x7fffffffffffffffL)
+ __builtin_abort ();
+
+ return 0;
+}