<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/54313>54313</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
Inefficient code generated in simple boolean expression
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
jamescooper-blis
</td>
</tr>
</table>
<pre>
In the code below, the function `check4` should return `true`.
It does not do this when using `&&`, but it does when using `&`.
```
static bool take4v1(bool a, bool b, bool c, bool d) {
return (a && b) || (a && c) || (a && d);
}
static bool take4v2(bool a, bool b, bool c, bool d) {
return a && (b || c || d); // Optimises better if & is used instead.
}
bool check4(bool a, bool b, bool c, bool d) {
return take4v1(a, b, c, d) == take4v2(a, b, c, d);
}
```
LLVM IR generated in the problematic case (-std=c++17 -O3):
```
define dso_local noundef zeroext i1 @_Z6check4bbbb(i1 noundef zeroext %0, i1 noundef zeroext %1, i1 noundef zeroext %2, i1 noundef zeroext %3) local_unnamed_addr #0 !dbg !18 {
call void @llvm.dbg.value(metadata i1 %0, metadata !22, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !26
call void @llvm.dbg.value(metadata i1 %1, metadata !23, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !26
call void @llvm.dbg.value(metadata i1 %2, metadata !24, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !26
call void @llvm.dbg.value(metadata i1 %3, metadata !25, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !26
call void @llvm.dbg.value(metadata i1 %0, metadata !27, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !33
call void @llvm.dbg.value(metadata i1 %1, metadata !30, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !33
call void @llvm.dbg.value(metadata i1 %2, metadata !31, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !33
call void @llvm.dbg.value(metadata i1 %3, metadata !32, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !33
%5 = or i1 %2, %3
%6 = or i1 %5, %1, !dbg !35
%7 = and i1 %6, %0, !dbg !35
call void @llvm.dbg.value(metadata i1 %0, metadata !36, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !42
call void @llvm.dbg.value(metadata i1 %1, metadata !39, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !42
call void @llvm.dbg.value(metadata i1 %2, metadata !40, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !42
call void @llvm.dbg.value(metadata i1 %3, metadata !41, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !42
%8 = xor i1 %0, true, !dbg !44
%9 = or i1 %8, %1, !dbg !44
%10 = select i1 %9, i1 %0, i1 %5, !dbg !44
%11 = xor i1 %10, %7, !dbg !45
%12 = xor i1 %11, true, !dbg !45
ret i1 %12, !dbg !46
}
```
LLVM IR in the correct case (same flags):
```
define dso_local noundef zeroext i1 @_Z6check4bbbb(i1 noundef zeroext %0, i1 noundef zeroext %1, i1 noundef zeroext %2, i1 noundef zeroext %3) local_unnamed_addr #0 !dbg !18 {
call void @llvm.dbg.value(metadata i1 %0, metadata !22, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !26
call void @llvm.dbg.value(metadata i1 %1, metadata !23, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !26
call void @llvm.dbg.value(metadata i1 %2, metadata !24, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !26
call void @llvm.dbg.value(metadata i1 %3, metadata !25, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !26
call void @llvm.dbg.value(metadata i1 %0, metadata !27, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !33
call void @llvm.dbg.value(metadata i1 %1, metadata !30, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !33
call void @llvm.dbg.value(metadata i1 %2, metadata !31, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !33
call void @llvm.dbg.value(metadata i1 %3, metadata !32, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !33
call void @llvm.dbg.value(metadata i1 %0, metadata !35, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !41
call void @llvm.dbg.value(metadata i1 %1, metadata !38, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !41
call void @llvm.dbg.value(metadata i1 %2, metadata !39, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !41
call void @llvm.dbg.value(metadata i1 %3, metadata !40, metadata !DIExpression(DW_OP_LLVM_convert, 1, DW_ATE_unsigned, DW_OP_LLVM_convert, 8, DW_ATE_unsigned, DW_OP_stack_value)), !dbg !41
ret i1 true, !dbg !43
}
```
gcc gets it right.
Assembly code for the problematic case:
```
check4(bool, bool, bool, bool): # @check4(bool, bool, bool, bool)
or edx, ecx
mov eax, edx
or eax, esi
and eax, edi
test esi, esi
cmovne edx, edi
and edx, edi
xor eax, edx
xor al, 1
ret
```
All instructions apart from the final three seem superfluous.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJztWVtvozgU_jXkxWoUDOTykIe2mZEqzaij1WpX2pfI2IfEU4Ij26SZ_fV7bMiFS1ajtg9RVGSB8blwPuxzwhenSvyaPxXEroFwJYCkkKvXgD76kawsuJWqIMF4xNfAX2LsELNWZS6IBltqL7K6BLwMg9EiGN0_WSIUGFIo10E_0pDXNRSkNLJYOf2Ajl1znUeSlpbI2qSrdvRan3G0av7WWGYlJ6lSObHsBeJdGNCpv2Xet-ulxx4_9kRAZySYPFRuCB4HNHTKSBWfM3RKj9ga4_zCuHMaRLXPYLI4D7wbKX1npMfHOj-HcPihU8eCwq_YyPPWyo00-IpTsBY0kZkzJzg1pQFBZGEsMDHsjb2KqJr-98V8mqPKgTt5s8oiWmA7ez09Sj3vt7kkqvO3b399J09_kBUUoJn1CP2K3mqV5rDxk8GZAff27owV-GB8xgO2cELuniP_qP5FJyCTBRBh1DJXnOW40MsCB8m_oBXscTWHJIhHy3_G1TtL8cCn4GhbMaCJT4F-UXhZRC-LXOTEx7Usi4JtQCyZEBpF0QhPoUhX7hJOzycItXOyU1K4wPN8txmi2nDHcsxrOt2AZYJZ5oHVIR_H0Bel7ZHF05f9VoMxWDvQweLv5fOPpZuTJVfFDrR1Bh4fiu7__IKhGrkqQNRDPdrT_9XG9OIvyzrgmW-PZ2gxUd6CNOwgjW4UaWcGaXyjSDszSJMbRdrN08m1I42ij8nTqIP9RpB28jTqYL8RpJ08ja7-V-aEFONP3OcMUfp84jysk8q4qZLUKmHLa3JmMvEmrBC1zbi2GV2yeV_FiMbX_s5j-kEVY3ajSDtZE199bXwj0k7FiK--Np6QYvxTn9v7Yz3w8-SpddMmPrOZNUvItL-ENEzCkbcxkAO3td2s5hNnhORUkPq9hK1ow7oEJZOW1Xn5CmnbKrwA8miFzPGgS1s64xYTJC2iRurLgQzKw98cWjvoB_pnkCSRLGcrc0762s4-Wd8n67s1pJ-s7_aQfrK-20P6yfpuD2mXa119RcLv6Y_J0-mNIu3m6fWzyrch7XKtq6-9J6Q1pehhHdFvMooV52QF1riNSy1Xaztsyu-NgU2a_6q2VDOkO317Txe5RnOzzcXYf3VshVw88NvfTeVv-zpu1rkDQ_YHiL3TAb5vyjdqV8lZJRf7C_a13Mim3P2F1bBvyS0Y6-Vo2GfPMQCkY8f42vZH_xfk-zrAS_Ef5CyvlmlDiAvowsTdYw65vVRd-n1zQ9iWaUsyrTbVhroskDratQZABg4bYsot6CwvVWmGAzGPxCyasYGVNof5UwFZJrmEwlYLqbGbaeRmm4OfPWAFgWOyDUqdz9fWbo1bYH7_dyXtukyHXG3wxuV2fbnDJfkTuTDeSmNKQAb8NYmjMBqs52EM6Xg8jqbxJMlCkURMJIzTdAIZZTThg5ylkJt5kDwElBbwSrwL7AfJYiDndETpKBrN3JcsTYZRxKeTWcQFiHGSxFNcmZgKMh_6UqP0aqDnPqS0RCKOFUgaa05CZny6g38c-melXSs9_4lU13Cl8CXepWgy8DHMPYb_ADMZyFs">