On Wed, Nov 24, 2021 at 09:45:16AM +0100, Richard Biener wrote:
> > Thinking more about it, perhaps we could do more for BIT_XOR_EXPR.
> > We could allow masked1 == masked2 case for it, but would need to
> > do something different than the
> >   n->n = n1->n | n2->n;
> > we do on all the bytes together.
> > In particular, for masked1 == masked2 if masked1 != 0 (well, for 0
> > both variants are the same) and masked1 != 0xff we would need to
> > clear corresponding n->n byte instead of setting it to the input
> > as x ^ x = 0 (but if we don't know what x and y are, the result is
> > also don't know).  Now, for plus it is much harder, because not only
> > for non-zero operands we don't know what the result is, but it can
> > modify upper bytes as well.  So perhaps only if current's byte
> > masked1 && masked2 set the resulting byte to 0xff (unknown) iff
> > the byte above it is 0 and 0, and set that resulting byte to 0xff too.
> > Also, even for | we could instead of return NULL just set the resulting
> > byte to 0xff if it is different, perhaps it will be masked off later on.
> > Ok to handle that incrementally?
> 
> Not sure if it is worth the trouble - the XOR handling sounds
> straight forward at least.  But sure, the merging routine could
> simply be conservatively correct here.

This patch implements that (except that for + it just punts whenever
both operand bytes aren't 0 like before).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2021-11-25  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/103376
        * gimple-ssa-store-merging.c (perform_symbolic_merge): For
        BIT_IOR_EXPR, if masked1 && masked2 && masked1 != masked2, don't
        punt, but set the corresponding result byte to MARKER_BYTE_UNKNOWN.
        For BIT_XOR_EXPR similarly and if masked1 == masked2 and the
        byte isn't MARKER_BYTE_UNKNOWN, set the corresponding result byte to
        0.

--- gcc/gimple-ssa-store-merging.c.jj   2021-11-24 09:54:37.684365460 +0100
+++ gcc/gimple-ssa-store-merging.c      2021-11-24 11:18:54.422226266 +0100
@@ -556,6 +556,7 @@ perform_symbolic_merge (gimple *source_s
   n->bytepos = n_start->bytepos;
   n->type = n_start->type;
   size = TYPE_PRECISION (n->type) / BITS_PER_UNIT;
+  uint64_t res_n = n1->n | n2->n;
 
   for (i = 0, mask = MARKER_MASK; i < size; i++, mask <<= BITS_PER_MARKER)
     {
@@ -563,12 +564,33 @@ perform_symbolic_merge (gimple *source_s
 
       masked1 = n1->n & mask;
       masked2 = n2->n & mask;
-      /* For BIT_XOR_EXPR or PLUS_EXPR, at least one of masked1 and masked2
-        has to be 0, for BIT_IOR_EXPR x | x is still x.  */
-      if (masked1 && masked2 && (code != BIT_IOR_EXPR || masked1 != masked2))
-       return NULL;
+      /* If at least one byte is 0, all of 0 | x == 0 ^ x == 0 + x == x.  */
+      if (masked1 && masked2)
+       {
+         /* + can carry into upper bits, just punt.  */
+         if (code == PLUS_EXPR)
+           return NULL;
+         /* x | x is still x.  */
+         if (code == BIT_IOR_EXPR && masked1 == masked2)
+           continue;
+         if (code == BIT_XOR_EXPR)
+           {
+             /* x ^ x is 0, but MARKER_BYTE_UNKNOWN stands for
+                unknown values and unknown ^ unknown is unknown.  */
+             if (masked1 == masked2
+                 && masked1 != ((uint64_t) MARKER_BYTE_UNKNOWN
+                                << i * BITS_PER_MARKER))
+               {
+                 res_n &= ~mask;
+                 continue;
+               }
+           }
+         /* Otherwise set the byte to unknown, it might still be
+            later masked off.  */
+         res_n |= mask;
+       }
     }
-  n->n = n1->n | n2->n;
+  n->n = res_n;
   n->n_ops = n1->n_ops + n2->n_ops;
 
   return source_stmt;


        Jakub

Reply via email to