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.