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.