Bug 101254 - [12 Regression] gcc head does not comply fully to -fwrapv since r12-1723
Summary: [12 Regression] gcc head does not comply fully to -fwrapv since r12-1723
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 12.0
: P1 normal
Target Milestone: 12.0
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2021-06-29 09:19 UTC by Fabien
Modified: 2021-06-29 19:10 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-06-29 00:00:00


Attachments
source file for above test (253 bytes, text/x-csrc)
2021-06-29 09:19 UTC, Fabien
Details
patch (664 bytes, patch)
2021-06-29 15:09 UTC, Andrew Macleod
Details | Diff
new patch (578 bytes, patch)
2021-06-29 15:42 UTC, Andrew Macleod
Details | Diff
another patch (860 bytes, patch)
2021-06-29 17:11 UTC, Andrew Macleod
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Fabien 2021-06-29 09:19:51 UTC
Created attachment 51079 [details]
source file for above test

-fwrapv does not work as expected on gcc head:

Previous expected behavior :

  sh> gcc --version
  gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0

  sh> gcc -O2 -fwrapv gcc_overflow.c 
  sh> ./a.out 
  1: 1
  0: 0
  0: 0

Behavior with head:

  sh> gcc --version
  gcc (GCC) 12.0.0 20210627 (461f937b)

  sh> gcc -O2 -fwrapv gcc_overflow.c 
  sh> ./a.out
  1: 1
  0: 0
  0: 1

But with the same :

  sh> gcc -O1 -fwrapv gcc_overflow.c 
  sh> ./a.out
  1: 1
  0: 0
  0: 0

Not that it seems that it was working fine with bc046a60 on 2021-06-18, so the regression may have been introduced after this date.
Comment 1 Jakub Jelinek 2021-06-29 09:34:36 UTC
Started with r12-1723-gae6b830f31a47aca7ca24c4fea245c29214eef3a
Adjusted testcase for testsuite:
/* PR tree-optimization/101254 */
/* { dg-do run } */
/* { dg-options "-O2 -fwrapv" } */

int
foo (long long imin, long long imax)
{
  if (imin > imax)
    return 0;
  else if (imax - imin < 0 || (imax - imin) + 1 < 0)
    return 0;
  return 1;
}

int
main ()
{
  long long imax = __LONG_LONG_MAX__;
  long long imin = -imax - 1; 
  if (!foo (-10, 10))
    __builtin_abort ();
  if (foo (-10, imax))
    __builtin_abort ();
  if (foo (imin, imax))
    __builtin_abort ();
  return 0;
}
Comment 2 Andrew Macleod 2021-06-29 15:09:58 UTC
Created attachment 51082 [details]
patch

I *think* this is correct.   but wrapv and signed stuff sometimes confuses me :-)
when -fwrapv is on,  +INf - -INF is -1 ?  is this correct?
in which case, the relations that were being added for minus were not quite correct in this case.

given    lhs = op1 - op2
if op1 > op2, we were producing a range of [1, +INF].  which is fine for unsigned.   but for signed, that edge condition for -INF means the range should be [0, +INF].
likewise, if op1 >= op2, then result range would be [0, +INF]
 
Is this is correct?   I hope that  -INF - -INF still equals 0 tho?  Thats the only other case that might need consideration.

The attached patch implements the above and appears to fix the test. I just want to be sure I have it right.
Comment 3 Jakub Jelinek 2021-06-29 15:21:40 UTC
INT_MAX - INT_MIN with -fwrapv is -1, indeed, and generally if
x > y then x - y < 0 iff x > y + INT_MAX.
Say
x = 1073741839
y = -1073741887
x > y && x - y (== -2147483570) < 0
Comment 4 Jakub Jelinek 2021-06-29 15:25:34 UTC
Anyway, I think you just can't assume anything for the SIGNED && TYPE_OVERFLOW_WRAPS case, the result can be anything (VARYING) both for the GT_EXPR and GE_EXPR.
Comment 5 Andrew Macleod 2021-06-29 15:42:32 UTC
Created attachment 51083 [details]
new patch

Ah right.  so op1 == op2 is the only time we can conclude anything.  Like so:
Comment 6 Jakub Jelinek 2021-06-29 15:47:07 UTC
Well, from x > y signed -fwrapv you can assume x - y to be ~[0, 0] (from x >= y nothing).
It is similar to unsigned, though in that case there are no negative values and so for x >= y x - y [0, max] is the actually VARYING and for x > y x - y [1, max]  is the same thing as ~[0, 0].
Comment 7 Jakub Jelinek 2021-06-29 15:48:44 UTC
BTW, rel of NE_EXPR, LE_EXPR or LT_EXPR never appear?  I guess one can always swap the two operands and thus transform LE_EXPR into GE_EXPR and LT_EXPR into GT_EXPR, but for EQ_EXPR vs. NE_EXPR that doesn't work.
Comment 8 Andrew Macleod 2021-06-29 15:55:11 UTC
I just never added them... I guess we could fully flesh out the combinations and results.   Note this is also the only non-relational operand that is even implemented so far..  Haven't gotten to any of the others yet.
Comment 9 Andrew Macleod 2021-06-29 17:11:14 UTC
Created attachment 51084 [details]
another patch

OK, fleshed it out.  Your observations about [0,max] for unsigned are true, but it was harmless.  however, when I broke it into 3 cases, unsigned, wrapping signed and nornmal signed, it looks like I can simply treat it as wrapping and non-wrapping.. since ~[0,0]for unsigned is the same as [1, max]
anyway I added the LT, LE, and NE cases as well.
   
I think this is now right and complete?  or have I missed something else.. certainly possible,I'm developing a headache thinking about it.
Comment 10 Jakub Jelinek 2021-06-29 17:38:13 UTC
Comment on attachment 51084 [details]
another patch

Except for some consistency (max is in comments lowercase, but MIN is uppercase), it looks good to me.
Slightly OT, wonder if something tries to handle even the swapped arguments,
i.e. relation op1 < op2 and subtraction op2 - op1.  But that can be done incrementally if not done yet...
Comment 11 Andrew Macleod 2021-06-29 18:27:04 UTC
(In reply to Jakub Jelinek from comment #10)
> Comment on attachment 51084 [details]
> another patch
> 
> Except for some consistency (max is in comments lowercase, but MIN is
> uppercase), it looks good to me.

latest version i had already switched those to +INF and -INF terminology.  Running thru testing now. 

> Slightly OT, wonder if something tries to handle even the swapped arguments,
> i.e. relation op1 < op2 and subtraction op2 - op1.  But that can be done
> incrementally if not done yet...

Not sure I follow.  Why would we be interested in swapping operands of a minus?
Comment 12 GCC Commits 2021-06-29 19:09:43 UTC
The master branch has been updated by Andrew Macleod <amacleod@gcc.gnu.org>:

https://gcc.gnu.org/g:a96d8d67d0073a7031c0712bc3fb7759417b2125

commit r12-1916-ga96d8d67d0073a7031c0712bc3fb7759417b2125
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Tue Jun 29 10:52:58 2021 -0400

    Fix MINUS_EXPR relations.
    
    Flesh out and correct relations for both wrapping and non-wrapping values.
    
            gcc/
            PR tree-optimization/101254
            * range-op.cc (operator_minus::op1_op2_relation_effect): Check for
            wrapping/non-wrapping when setting the result range.
    
            gcc/testsuite
            * gcc.dg/pr101254.c: New.
Comment 13 Andrew Macleod 2021-06-29 19:10:49 UTC
Fix should be checked in.