| Issue |
64774
|
| Summary |
Flag `--canonicalize` is broken in `mlir-opt` with LLVM 16
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
azteca1998
|
## 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.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs