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; }