https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97812
--- Comment #9 from Richard Biener <rguenth at gcc dot gnu.org> ---
(In reply to Martin Liška from comment #8)
> Started with r9-4558-g476a31b55b5471262.
>
> Slightly modified test-case:
>
> $ cat pr97812.c
> char c;
>
> int main() {
> volatile short b = 4066;
> unsigned d = b & 2305;
> signed char e = d;
> c = e ? : e;
> if (!d)
> __builtin_abort ();
> return 0;
> }
>
> @Richi: You can reproduce that on needle machine (su mliska):
> $ cd /tmp/
> $ gcc pr97812.c -O2 -flto -fdump-tree-all -o a.out && ./a.out
> Aborted (core dumped)
Why would you need -flto? Can you share dumps of the previous pass
of where it goes wrong? I also fail to see why it would need aarch64,
there's no piece that should influence GIMPLE.
Hmm, OK. So a cross shows differences in the initial IL from the FE:
volatile short int b = 4066;
- unsigned int d = (unsigned int) b & 2305;
+ unsigned int d = (unsigned int) (unsigned short) b & 2305;
signed char e = (signed char) d;
the GIMPLE dump reveals association:
- _2 = (unsigned int) b.0_1;
- d = _2 & 2305;
+ b.1_2 = (unsigned short) b.0_1;
+ _3 = (unsigned int) b.1_2;
+ d = _3 & 2305;
for some reason on aarch64 we are zero-extending b only on aarch64.
>From here things go downhill.
Ah, the difference stems from fold_unary which does
/* Convert (T)(x & c) into (T)x & (T)c, if c is an integer
constants (if x has signed type, the sign bit cannot be set
in c). This folds extension into the BIT_AND_EXPR.
??? We don't do it for BOOLEAN_TYPE or ENUMERAL_TYPE because they
very likely don't have maximal range for their precision and this
transformation effectively doesn't preserve non-maximal ranges. */
if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (op0) == BIT_AND_EXPR
&& TREE_CODE (TREE_OPERAND (op0, 1)) == INTEGER_CST)
{
..
if (change
&& !flag_syntax_only
&& (load_extend_op (TYPE_MODE (TREE_TYPE (and0)))
== ZERO_EXTEND))
{
tree uns = unsigned_type_for (TREE_TYPE (and0));
and0 = fold_convert_loc (loc, uns, and0);
and1 = fold_convert_loc (loc, uns, and1);
on x86_64 load_extend_op (HImode) returns UNKNOWN while on aarch64 it
returns ZERO_EXTEND.
Not sure why we do this kind of thing so prematurely here :/
Then one needs -funsigned-char to reproduce it on x86_64 but indeed only with
-flto ...
So, testcase failing on x86_64 with -O2 -flto:
unsigned char c;
int main()
{
volatile short b = 4066;
unsigned short bp = b;
unsigned d = bp & 2305;
signed char e = d;
c = e ? : e;
if (!d)
__builtin_abort ();
return 0;
}