<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/64774>64774</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
Flag `--canonicalize` is broken in `mlir-opt` with LLVM 16
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
azteca1998
</td>
</tr>
</table>
<pre>
## LLVM version
LLVM 16.0.6 in both Linux and Mac OS.
## MLIR input
```mlir
module {
func.func public @felt2bool(%arg0: i252) -> !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)> attributes {llvm.emit_c_interface} {
%c1_i64 = arith.constant 1 : i64
%0 = llvm.alloca %c1_i64 x !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)> {alignment = 1 : i64} : (i64) -> !llvm.ptr<struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>>
%c1_i64_0 = arith.constant 1 : i64
%1 = llvm.alloca %c1_i64_0 x !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)> {alignment = 1 : i64} : (i64) -> !llvm.ptr<struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>>
cf.br ^bb1(%arg0 : i252)
^bb1(%2: i252): // pred: ^bb0
cf.br ^bb2(%2 : i252)
^bb2(%3: i252): // pred: ^bb1
cf.br ^bb3(%3 : i252)
^bb3(%4: i252): // pred: ^bb2
cf.br ^bb4
^bb4: // pred: ^bb3
%c1_i252 = arith.constant 1 : i252
cf.br ^bb5(%c1_i252 : i252)
^bb5(%5: i252): // pred: ^bb4
cf.br ^bb6(%5 : i252)
^bb6(%6: i252): // pred: ^bb5
cf.br ^bb7(%3 : i252)
^bb7(%7: i252): // pred: ^bb6
cf.br ^bb8(%5 : i252)
^bb8(%8: i252): // pred: ^bb7
cf.br ^bb9(%7, %8 : i252, i252)
^bb9(%9: i252, %10: i252): // pred: ^bb8
%11 = arith.extui %9 : i252 to i256
%12 = arith.extui %10 : i252 to i256
%13 = arith.subi %11, %12 : i256
%c3618502788666131213697322783095070105623107215331596699973092056135872020481_i256 = arith.constant 3618502788666131213697322783095070105623107215331596699973092056135872020481 : i256
%14 = arith.addi %13, %c3618502788666131213697322783095070105623107215331596699973092056135872020481_i256 : i256
%15 = arith.cmpi ult, %11, %12 : i256
%16 = arith.select %15, %14, %13 : i256
%17 = arith.trunci %16 : i256 to i252
cf.br ^bb10(%17 : i252)
^bb10(%18: i252): // pred: ^bb9
cf.br ^bb11(%18 : i252)
^bb11(%19: i252): // pred: ^bb10
%c0_i252 = arith.constant 0 : i252
%20 = arith.cmpi eq, %19, %c0_i252 : i252
cf.cond_br %20, ^bb12, ^bb17
^bb12: // pred: ^bb11
cf.br ^bb13
^bb13: // pred: ^bb12
%21 = llvm.mlir.undef : !llvm.struct<()>
cf.br ^bb14(%21 : !llvm.struct<()>)
^bb14(%22: !llvm.struct<()>): // pred: ^bb13
%true = arith.constant true
%23 = llvm.mlir.undef : !llvm.struct<(i1, array<0 x i8>, struct<()>)>
%24 = llvm.insertvalue %true, %23[0] : !llvm.struct<(i1, array<0 x i8>, struct<()>)>
%25 = llvm.insertvalue %22, %24[2] : !llvm.struct<(i1, array<0 x i8>, struct<()>)>
%26 = llvm.bitcast %1 : !llvm.ptr<struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>> to !llvm.ptr<struct<(i1, array<0 x i8>, struct<()>)>>
llvm.store %25, %26 {alignment = 1 : i64} : !llvm.ptr<struct<(i1, array<0 x i8>, struct<()>)>>
%27 = llvm.load %1 {alignment = 1 : i64} : !llvm.ptr<struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>>
cf.br ^bb15(%27 : !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>)
^bb15(%28: !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>): // pred: ^bb14
cf.br ^bb16
^bb16: // pred: ^bb15
cf.br ^bb22(%28 : !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>)
^bb17: // pred: ^bb11
cf.br ^bb18(%19 : i252)
^bb18(%29: i252): // pred: ^bb17
cf.br ^bb19
^bb19: // pred: ^bb18
%30 = llvm.mlir.undef : !llvm.struct<()>
cf.br ^bb20(%30 : !llvm.struct<()>)
^bb20(%31: !llvm.struct<()>): // pred: ^bb19
%false = arith.constant false
%32 = llvm.mlir.undef : !llvm.struct<(i1, array<0 x i8>, struct<()>)>
%33 = llvm.insertvalue %false, %32[0] : !llvm.struct<(i1, array<0 x i8>, struct<()>)>
%34 = llvm.insertvalue %31, %33[2] : !llvm.struct<(i1, array<0 x i8>, struct<()>)>
%35 = llvm.bitcast %0 : !llvm.ptr<struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>> to !llvm.ptr<struct<(i1, array<0 x i8>, struct<()>)>>
llvm.store %34, %35 {alignment = 1 : i64} : !llvm.ptr<struct<(i1, array<0 x i8>, struct<()>)>>
%36 = llvm.load %0 {alignment = 1 : i64} : !llvm.ptr<struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>>
cf.br ^bb21(%36 : !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>)
^bb21(%37: !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>): // pred: ^bb20
cf.br ^bb22(%37 : !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>)
^bb22(%38: !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>): // 2 preds: ^bb16, ^bb21
cf.br ^bb23(%38 : !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>)
^bb23(%39: !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>): // pred: ^bb22
cf.br ^bb24(%39 : !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>)
^bb24(%40: !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>): // pred: ^bb23
return %39 : !llvm.struct<(i1, array<0 x i8>, struct<()>, array<0 x i8>)>
}
}
```
## Expected behaviour
When calling `felt2bool::felt2bool::felt_to_bool` with `0`, `1`, and `2` it should return `false`, `true`, `false` (the first value of the returned struct, aka the `i1`). Invoking it after conversion without canonicalization works as expected, however when adding the `--canonicalize` flag it returns the wrong value when the argument is `0`.
In other words, for an input of `0`, `1` and `2`, the outputs are:
- Expected: `false`, `true`, `false` (works correctly without `--canonicalize`).
- Actual: `false`, `true`, `false` (actual behaviour with `--canonicalize`).
## Steps to reproduce
Write the following piece of code in `felt2bool.c`:
```c
#include <stdint.h>
#include <stdio.h>
void _mlir_ciface_felt2bool(uint8_t *dst, uint64_t, uint64_t, uint64_t, uint64_t);
int main()
{
size_t i;
uint8_t dst;
for (i = 0; i < 3; i++)
{
_mlir_ciface_felt2bool(&dst, i, 0, 0, 0);
printf("felt2bool(%lu) = %s\n", i, dst ? "true" : "false");
}
return 0;
}
```
Store the MLIR code as `felt2bool.mlir`. Then, compile the source code into LLVM IR both with and without `--canonicalize`:
```bash
cat felt2bool.mlir | mlir-opt-16 --convert-scf-to-cf --convert-func-to-llvm | mlir-translate-16 --mlir-to-llvmir > felt2bool-ok.ll
cat felt2bool.mlir | mlir-opt-16 --canonicalize --convert-scf-to-cf --convert-func-to-llvm | mlir-translate-16 --mlir-to-llvmir > felt2bool-err.ll
```
Build binaries for both versions:
```bash
clang-16 felt2bool.c felt2bool-ok.ll -o felt2bool-ok
clang-16 felt2bool.c felt2bool-err.ll -o felt2bool-err
```
Execute them:
```bash
./felt2bool-ok
./felt2bool-err
```
The output will be as follows:
```
$ ./felt2bool-ok
felt2bool(0) = false
felt2bool(1) = true
felt2bool(2) = false
$ ./felt2bool-err
felt2bool(0) = true
felt2bool(1) = true
felt2bool(2) = false
```
The `felt2bool-err`'s `felt2bool(0)` should print `false` to be correct.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzkWl-P2y7W_jTMDUqEwcb2RS7mr1Sp1Sv9Wr17GWFMErYOZDGemfbTr8DYsRN7mtntpKvdUZRxgHOe5xzgnINtVtdyq4RYgeQOJA83rLE7bVbspxWcRXme3RS6_LECmABM4OfP__8FPgtTS60AegDotv327RFdoiWFUsFC2x38LFXzCpkq4RfG4f99XQ4Fgr4vnz_9BaU6NHbUSVH72VfStE17XTaVgCC9a3_DTaP40n3BQ1NUkkMQo42oLC60rgDOAE6Y2SJAbqHECQY4hwtAHiHAUVU975e1NQ23gNwDnMkI4HvIjGE_ALlH8BXKDJBH1zgcBnAeWieGui7IrDWyaKyoHVOPI_bSrvlaKivMhnEB0oeBFQAnPFpLGkNAHiAz0u6WXKvaMmVhBD17GofBELrxyA_1ullVac4GSl4_1jyQ3rFKbtVeKOtZHBk6q4izJ3O_Tp19sAaQ-4_g5D5D77SOWKPL_RnN-3ON_tc9yjfLwkCQPBZFdNxUcLCrurHDMXjYT1wnfgL4CR6MKL1NbiyaRMFBwyxEGEAugYgmIUjQMAsRBsSXQOBJiHikL56VJmdrtzV9buk6MlN4Scv4qGDasDAsucSweBKIBg2zEGEAvQQimYRIfzU9YUB6CQSdhMh-ZUUYkF0CkQbJgf68Y4jv3bxmA5z7SbwgkA_HudCELiGQjcNZNFg_4tU20rXmPQVotftPx0J4SihCv5AiA6m6KVqhqCPfr0M6SHaERlmCcJpllNKIRDgiNE8JxmlGUJ6gFEUooZhEKMVRQkiU5JTmeZ4SlGOU0IgkWYoRRnHmFzud2i2_E-TUiGD6MGGzsmxNJ8H0D7FyikUytH5_kLCpbOf--XkIwkPX1aIS3LY6O7m4uyAzCtKBAmsaxWWvtx0eVg0-3yERale81zGTS7ohF-3CfDpnRZ2OeZhuSH5RRkHjiI1mIzaaiNgusaHTKRP_6Pycd8sHnYTx3n1cq3LtjHOK_GhPCh8v07FxeN6S6eQYkbECMq_gxLBBHeXK9mWjSrEJJcx5BRVqjUkKcagBol9Jn05lJ4h_LTdr1TglW9OIqdl17ceohsm7bH9npTZwlMOKj1hS1cLYZ1Y5ki3ZsIQwAckdAsnD7yQBxxOezBLBXQLDMUju8MfSoEcahbSc1bar6m-vUy27KPfbgM4q8OAxbVrPdtHZmX3B2eGjWDkG6dHxlWZl8Pr1SF1wghlGlVD84vR3rcV5_NO41EFn10CejWzTFX1Ex1zpvILk3Ku4O69l1_dq-u7clnWpfqIaGI3AlxUD6TTMCc83FIxLd4J-VwrFoXYi6J0ptBeM_o0Umh-z1YZV9WQC9R1j6_GVkmiAI7Ppq-XWxlmCPzyRkvmMTroinpAPT6QkmUyk6L8zkZLudOPM_rOJlNDzRIr-wxLpSXgJZyZCrx71e-j0T-ZSPHPzsrs5ef0ao4e-do2BvWfqY_Sn_WEUT6dh3N2AvX7N0EPnf3T1TN_ExXFH7vp-CdAx-qN-GZy9jbCNUfBK7uh8kT6EB5D9RfckcuLZ5ePrQXArSliIHXuWujHDQX_bCQU5qyqpthDQwbNJcgvI7cTPtdVr30IRfJF256Q8tNtPFEXhkqnS_cRumLSw3ummKnt_UdRWL72YvynQ_-o6IcCZ3Qm4kaa2sK039Aa6plaTKDsXOsjvzHcBimRLI1_CT-pZf3fGSQvZxgoDuVbh0bDnrxsLOVNaSc4q-ZNZ36HN9xqyGorgPad_p1_EszDwxfmMlaXTGvAWi4EKz3xTMY_Z8qz9wBej1TaY4ZW4Rma2jc-esu5cOXoE_UlBbXcOVpuydjw22kCm2ufRzh3nEzD0vmt2OLqxh8bWkBnhJjOspUW_Pvzqfce8tC7i2hjBbfWj9-WUN9xMHBFvuW1Y9V485qWOq7hffG-gjTbCVysOtSvejDgYXTZcjDaCkVZ4R210VekXN7kHKbhfcFyXAko12iBL7qDI6bsAvMeUildN6Y4V97UtpbLLXb-Jz7v1sHfw_axlCdfupLHmcsO4WA9fH2ikstnaVcC3Ze03gWuh8frC6xyQu3NMqSzcM6lCUAqx5u4Y9mr5U6wtlL20a-y4OCJjra7XLVoXC32RiAC5g-7yHhJ_CfCd_wzujx8BZ60HmAarpftCw698xM39HYxUduPF8MkrGFUDcO6ZAZzUILlXoL056PWW7ohBniDAuL13iUOox-EIhk_hjoH5NFOgo2veDN5f_QnALUf_7olfgKweL0D_2glFS_htJ5QjyvX-IKtWrNaN4aJbuVa378R8-qt96cXvHRck3ty15HbydZeC1bu2iTMLx3wgSO-hu1jog11EFC4Wbby1i5pvFlYv-GbQtmkUd40uZx5FrWGqrpgVrYK2rR3kEMjjEXShvy-r6j1sBjZ-ODlhTM9ucprvGlmVsJCKGSlqv0n8_IQEVZ_Hl4HzK6a2jsQgJJ06Bi70qOkiyZb1WFQY84YZj6-CN2343L9FeQnw0zmdcevbSN_6TAZfZOXSgdsWbcie8FYXbWN4Ch3uKgwDAeqCwOCuz7A_6vqPj1WG3XhC_BxZGPMW9LTqfwV57IJvbZ0ydrNLlek4qAQuLueGks2HzVEyttq5PWT-5U25ImVOcnYjVhHNMc7SmCQ3u1VeFLwQaVKyYpOlKENZROKcpBtEKUcJupErjDBBWZRGSYJIstyUuSApRaJI8iKhBYiR2DNZLX1Jrc32RtZ1I1Y0TtP4pmKFqGr_QiDGSrxA3-micfJwY1ZOZlE02xrEqJK1rY9arLSVWD25Cm2ydpM1LIz-LlTI-V0E6Uve8B7hTWOq1c7ag195_qiwlXbXFEuu9wA_OcDwb3Ew-u_C1alPnmYN8JM3458BAAD__5tp4Xo">