https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115993

            Bug ID: 115993
           Summary: `((A&B)^C)^B` or `(~A & B) ^ C` is more canonical
           Product: gcc
           Version: 15.0
            Status: UNCONFIRMED
          Keywords: missed-optimization
          Severity: enhancement
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: pinskia at gcc dot gnu.org
  Target Milestone: ---

Take:
```
int f2(int A, int B, int C)
{
  return ((A&B)^C)^B; // (~A & B) ^ C
}
int f3(int A, int B, int C)
{
  return (~A & B) ^ C;
}

int f(int A, int B, int C)
{
        return f2(A,B,C) == f3(A,B,C);
}
```

These f2/f3 on aarch64 produce the same code but don't on most other targets.

Pre is able to figure out that f2 and f3 are the same too.

  _10 = A_3(D) & B_4(D);
  _17 = B_4(D) ^ C_5(D);
  _12 = _10 ^ _17;
  _7 = ~A_3(D);
  _6 = B_4(D) & _7;
  _9 = C_5(D) ^ _6;
  _1 = _9 == _12;

Value numbering stmt = _9 = C_5(D) ^ _6;
Applying pattern match.pd:1528, gimple-match-2.cc:424
// (~A & B) ^ C -> (A & B) ^ (C ^ B) if (C ^ B) can be simplified
Match-and-simplified C_5(D) ^ _6 to _12

(C ^ B) simplifies down to _17 and (A & B) simplifies down to _10 so the whole
expression is _12.

So for constant, C, we use (~A & B) ^ C form.
So for constants, A and B, we also use (~A & B) ^ C form.

So maybe then (~A & B) ^ C should be the canonical form; even though we do try
if simplify that into the other form if some parts simplify.

Reply via email to