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

Reply via email to