https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118254

Andrew Macleod <amacleod at redhat dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |amacleod at redhat dot com

--- Comment #1 from Andrew Macleod <amacleod at redhat dot com> ---
Im not sure __builtin_unreachable works this way.  It does tell the compiler
that a basic block may not be reached, but its a hint.. It doesn't guarantee
any code after it will be eliminated.    It generally maps to nothing, so the
net effect may be to simply fold away the if.

A more correct test would be to change the unreachable call to a return.  Then
foo() should be eliminated.

I have adjusted the testcase to

void foo(void);
int il=1000;

int m1(void)
{
  short t = il;
  unsigned t1 = t;
  if (t1 == 0) {
    char b = t1;
    if (b != 1) 
      return 0;
    foo();
  }
  return 0;
}

int m2(void)
{
  short t = il;
  unsigned t1 = t;
  if (t1 == 0) {
    char b = il;
    if (b != 1) 
      return 0;
    foo();
  }
  return 0;
}

Which does accurately demonstrate that we do miss out on this during casts.
the m1() quite surprised me.

After looking into it, it seems to be for 2 reasons:
1) when performing a cast, we cast sub pairs, and when this gets to VARYING< we
immediately return to "save time".    This bypasses updating the bitmask for a
truncating cast usually.

2) furthermore operator_cast::op1_range makes no attempt to set a bitmask for
truncating casts: 

=========== BB 2 ============
Partial equiv (t_4 pe16 il.0_1)
    <bb 2> :
    il.0_1 = il;
    t_4 = (short int) il.0_1;
    t1_5 = (unsigned int) t_4;
    if (t_4 == 0)
      goto <bb 3>; [INV]
    else
      goto <bb 6>; [INV]

t1_5 : [irange] unsigned int [0, 32767][4294934528, +INF]
2->3  (T) il.0_1 :      [irange] int [-INF, -65536][0, 0][65536, +INF]
2->3  (T) t_4 :         [irange] short int [0, 0]
2->3  (T) t1_5 :        [irange] unsigned int [0, 32767][4294934528, +INF]

=========== BB 3 ============
Imports: il.0_1
Exports: il.0_1  b_6
         b_6 : il.0_1(I)
il.0_1  [irange] int [-INF, -65536][0, 0][65536, +INF]
Partial equiv (b_6 pe8 il.0_1)
    <bb 3> :
    b_6 = (char) il.0_1;
    if (b_6 != 1)
      goto <bb 4>; [INV]
    else
      goto <bb 5>; [INV]

3->4  (T) il.0_1 :      [irange] int [-INF, -65536][0, 0][65536, +INF]
3->4  (T) b_6 :         [irange] char [-INF, 0][2, +INF]

We know in BB2 that t_4 shares the lower 16 bits with il.0_1 as shown by the
PE16 partial equivalency relation.
We also know in BB3 that t_4 is [0, 0], AND we know that b_6 shares the lower 8
bits of i1.0_1 via the PE8 partial equivalency.

Whats lost is that although we know that the lower 16 bits of il.0_1 and t_4
are the same, we only adjust il.0_1... but do not reflect it in a bitmask.

When looking at the range calculated for i1.0_1 on exit from bb2 it calculates:
32      GORI    compute op 1 (il.0_1) at t_4 = (short int) il.0_1;
        GORI      LHS =[irange] short int [0, 0]
        GORI      Computes il.0_1 = [irange] int [-INF, -65536][0, 0][65536,
+INF] intersect Known range : [irange] int VARYING
        GORI    TRUE : (32) produces  (il.0_1) [irange] int [-INF, -65536][0,
0][65536, +INF]


If we set the bitmask on this to match the LHS range, we get
int [-INF, -65536][0, 0][65536, 2147418112] MASK 0xffff0000 VALUE 0x0

And when we allow the bitmask to be updated in fold_range properly, this will
set b_6 to the expected [0, 0] range.

Patch is in testing, and causes both functions to fold to 
return 0

Reply via email to