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