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

Reply via email to