https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124809
--- Comment #6 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
And the same with some auto var renames, so that there is no confusion for what
is from which function:
unsigned short a, c, d;
short
foo (short g, short h)
{
return h;
}
short
bar (short g, short h)
{
return g;
}
__attribute__((noipa)) void
baz (int b)
{
__builtin_abort ();
}
__attribute__((noinline)) int
qux (signed char g)
{
unsigned short j;
int b = 0, k;
while (d < 8)
{
if ((b = a != g) ^ a)
{
j = b + a;
k = j;
return a ? 0 : k >> a;
}
b = foo (d && c, a);
}
baz (b);
return 100;
}
__attribute__((noinline)) int
fred (signed char p)
{
unsigned short o;
int m = 0, n;
while (d < 8)
{
if ((m = a != p) ^ a)
{
o = m + a;
n = o;
return a ? 0 : n >> a;
}
m = bar (a, d && c);
}
baz (m);
return 100;
}
int
main ()
{
if (qux (1) != 1 || fred (1) != 1)
__builtin_abort ();
}
At runtime in both cases a is 0 and b/m are 1, so the right shift is 1.
Figuring out that it is >> 0 is correct, and that because it is in ?: last
operand
b + a or m + a is equal to just b or m and that it is [0, 1] is correct, but
somehow it only thinks about [0, 0] and not [0, 1].