<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/128778>128778</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[AArch64] `!struct.x && !struct.y` produces worse code than `(struct.x == 0) && (struct.y == 0)`
</td>
</tr>
<tr>
<th>Labels</th>
<td>
backend:AArch64,
llvm:instcombine
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
Kmeakin
</td>
</tr>
</table>
<pre>
`!it.x && !it.y` produces worse code than `(it.x == 0) && (it.y == 0)` if `it` is a struct type with `bool` members `x` and `y`.
Oddly using a `uint8_t` for `x` and `y` does not suffer from this problem.
# Real-world motivation
[This struct from mimalloc](https://github.com/microsoft/mimalloc/blob/a857a04803175cb51e1016339bda5b7993530729/include/mimalloc/types.h#L255)
```c++
// The `in_full` and `has_aligned` page flags are put in a union to efficiently
// test if both are false (`full_aligned == 0`) in the `mi_free` routine.
typedef union mi_page_flags_s {
uint8_t full_aligned;
struct {
uint8_t in_full : 1;
uint8_t has_aligned : 1;
} x;
} mi_page_flags_t;
```
# C++ code
https://godbolt.org/z/1387M789s
```c++
#include <cstdint>
struct S1 {
bool x;
bool y;
};
struct S2 {
bool x : 1;
bool y : 1;
};
struct S3 {
uint8_t x : 1;
uint8_t y : 1;
};
struct S4 {
uint8_t x ;
uint8_t y ;
};
extern "C" {
auto src1(S1 it) -> bool { return !it.x && !it.y; }
auto tgt1(S1 it) -> bool { return (it.x == 0) && (it.y == 0); }
auto src2(S2 it) -> bool { return !it.x && !it.y; }
auto tgt2(S2 it) -> bool { return (it.x == 0) && (it.y == 0); }
auto src3(S3 it) -> bool { return !it.x && !it.y; }
auto tgt3(S3 it) -> bool { return (it.x == 0) && (it.y == 0); }
auto src4(S4 it) -> bool { return !it.x && !it.y; }
auto tgt4(S4 it) -> bool { return (it.x == 0) && (it.y == 0); }
}
```
# AArch64 assembly
```asm
src1:
tst x0, #0x100
eor w9, w0, #0x1
cset w8, eq
and w0, w8, w9
ret
tgt1:
mov w8, #257
tst x0, x8
cset w0, eq
ret
src2:
tst x0, #0x2
eor w9, w0, #0x1
cset w8, eq
and w0, w8, w9
ret
tgt2:
tst x0, #0x3
cset w0, eq
ret
src3:
tst x0, #0x3
cset w0, eq
ret
tgt3:
tst x0, #0x3
cset w0, eq
ret
src4:
tst x0, #0xffff
cset w0, eq
ret
tgt4:
tst x0, #0xffff
cset w0, eq
ret
```
# Alive proof
https://alive2.llvm.org/ce/z/JRwXu7
```llvm
----------------------------------------
define i1 @src1(i64 %#0) nofree willreturn memory(none) {
#1:
%#2 = trunc i64 %#0 to i1
%#3 = and i64 %#0, 256
%#4 = icmp eq i64 %#3, 0
%#5 = xor i1 %#2, 1
%#6 = and i1 %#4, %#5
ret i1 %#6
}
=>
define i1 @tgt1(i64 %#0) nofree willreturn memory(none) {
#1:
%#2 = and i64 %#0, 257
%#3 = icmp eq i64 %#2, 0
ret i1 %#3
}
Transformation seems to be correct!
----------------------------------------
define i1 @src2(i64 %#0) nofree willreturn memory(none) {
#1:
%#2 = trunc i64 %#0 to i1
%#3 = and i64 %#0, 2
%#4 = icmp eq i64 %#3, 0
%#5 = xor i1 %#2, 1
%#6 = and i1 %#4, %#5
ret i1 %#6
}
=>
define i1 @tgt2(i64 %#0) nofree willreturn memory(none) {
#1:
%#2 = and i64 %#0, 3
%#3 = icmp eq i64 %#2, 0
ret i1 %#3
}
Transformation seems to be correct!
----------------------------------------
define i1 @src3(i64 %#0) nofree willreturn memory(none) {
#1:
%#2 = and i64 %#0, 3
%#3 = icmp eq i64 %#2, 0
ret i1 %#3
}
=>
define i1 @tgt3(i64 %#0) nofree willreturn memory(none) {
#1:
%#2 = and i64 %#0, 3
%#3 = icmp eq i64 %#2, 0
ret i1 %#3
}
Transformation seems to be correct!
----------------------------------------
define i1 @src4(i64 %#0) nofree willreturn memory(none) {
#1:
%#2 = and i64 %#0, 65535
%#3 = icmp eq i64 %#2, 0
ret i1 %#3
}
=>
define i1 @tgt4(i64 %#0) nofree willreturn memory(none) {
#1:
%#2 = and i64 %#0, 65535
%#3 = icmp eq i64 %#2, 0
ret i1 %#3
}
Transformation seems to be correct!
Summary:
4 correct transformations
0 incorrect transformations
0 failed-to-prove transformations
0 Alive2 errors
```
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzUWE1zo7oS_TXypisp0QIDCy-cZLx4H_WqZmbxdikBwtYdQBlJxPb99bda4BgnzkxyJ5lbcaVicB-dPv0hISSd0-tOqQVLrlhyM5O93xi7-Her5DfdzQpT7RdszhlG2l_ugOGc4RyG2z2bc7izpupL5WBrrFNQmkqB38gOwqhsGCVumLgBzjA_MpBpPzURm65pnPbh2oEE521fevD7OwVb7TdkLoxpCNCqtlDW0U87upddRdck65LxJePL_1VVs4fe6W4Nkmy97nx2G-hrY8-NhMooB53x4Pq6VhZqa1rwG-0o1KJR7cjNUMBnJZuLrbFNBa3x-l56bTqyJVdfacSoPlC0upVNY0qW3DDMNt7fOSaWDFcMV2vtN31xWZqW4arVpTXO1D5cj4NwVTSmYLiSWZJKHmdcRGlSFkmkIh7NhciLSiZFmuciETzFnOFKd2XTV-qUhjLpLjcMxX8wSSjtfEmlCn8lwyv646Mu-LpRoSDdbd03zSRVG-luZUOtU4UukGsFdSPXDqRVcNd70B1I6DttOvAGVF3rUqvON_sju1fOU8kL4zdhXC0bp6g32JyTw4OLY5vMQxPpDvygrNW3tVWKNFjTe90pKg8FWal6dN_qW9J3G_TdOmApRQgwNgNMPTEx2MbKHaBH8JgKYGIJ0QF9NE_ycgph6Q3shhu6PNXkR8OhDscOux4qEuYV48tHbWOqwjT-0tg1w9WfDFeRyNL_plnunquqGJsCmLguna9055n4NPgbY_4STcKmuXbQ_XC_f4hjvDiOxSdjH2dqYJj-eo5HnEn9E6qD4ads8TNs54gec6idV7YDhnjN8BCe7L0BZ8uIYfYlAu2pKy-Y-DSEx9IrsMr3YdzZlVNcUUccmPzav4TpVavpg4eJXCQn-BZyX8L0y3IFORFvIfclTL8sNyYn8VvIfQnT35Q7_H-60CyXttzMY5DOqbYYVukDSrqWJhO1uyA8eOdp2sCOM7wGhoLvIs7HyUQfZWz43uYE2E5gE1DpVKDZZmRW3ycmesoEUxg5ALb5BGCVH7SHqTOoGj-tuYcjLUOBSToxn2rfZecE8SeCHvyFWfRsFvCfygGe5uCMNPH6QMWbk4ap-A5K45-S1nVdv17sO_CemXqNvle0uzT1k0e8JBteNs19Oz7mSzU-6__1efv_Pp1SEmqgvXjhh_FlpWrdKdARsJiPjzQ9j4FhQgHSwtIZ2mPBVjfNuPy0qjV2zzDrTKfC2pOO-4uHyTiMR1qGwNu-K2HCSltCHU1wIuCo5U98XwMm8wksDjBdtnegvk-ggqB8AkwCcGdsCGyQQpipz_nR5wETD3UNDAFplT9a58cFlNbWT4-zNz7G3zp7Z7OSPkne06zgMSsncYiHOL5a2bna2Da8uYBTqnVUm4Le5KxVpWcYjZ36S12Fv7erftZUb95S79dR75G5MykRH6ufxEfKyrO1_VBR_Lbaxr8nK_MkGafku9X3w0Xyihp_6dtW2v1BYnwAgD_hcMHKQXc_ttdSN6q68Obizpp79QwqbJUQlLXGnpxxzKqFqHKRy5laRGnME4xEwmebBWZpjpGMZYkRj5NqXkZ1WqZZzNM0yctyphfIMeGICSLPeX6ZxhWmVSXzrBJFJFMWc9VK3TxswmbauV4tIszSNJs1slCNC-eniIUsv6muYmI5vk8xpKQzxLA3E0vdOV-attBUamTJzcwuyHRR9GvHYt5o593Rk9e-CWezB7rkZjhYjYajjZN3yfGnlxzLHkeffX88MD06np31tln84OQyxDh8URX_CO2yCtlyDFdjwu4X-FcAAAD__wkJ678">