- 
                Notifications
    
You must be signed in to change notification settings  - Fork 15.1k
 
Closed
Labels
Description
LLVM version
LLVM 16.0.6 in Linux.
MLIR input
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:
#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:
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.llBuild binaries for both versions:
clang-16 felt2bool.c felt2bool-ok.ll -o felt2bool-ok
clang-16 felt2bool.c felt2bool-err.ll -o felt2bool-errExecute them:
./felt2bool-ok
./felt2bool-errThe 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.