llvm / clangir

A new (MLIR based) high-level IR for clang.
https://clangir.org
Other
307 stars 84 forks source link

[ThroughMLIR] cir-opt can not work when lowering ForOp to scf #680

Closed wenhu1024 closed 2 weeks ago

wenhu1024 commented 3 weeks ago

Hello, I am a newcomer. I meet an issue when use cir-opt to lower ForOp to scf. Here are some details.

  1. I write a c code first. for.c is here
void foo() {
        for (int a = 0; a < 2; a++) {
        }
}



  1. Then I use clang to get cir file.
    clang -cc1 -emit-cir for.c -o for.cir

Here is the for.cir I get.

!s32i = !cir.int<s, 32>
#fn_attr = #cir<extra({inline = #cir.inline<no>, nothrow = #cir.nothrow, optnone = #cir.optnone})>
module @"/home/wenhu/clangir/build/Release/bin/for.c" attributes {cir.lang = #cir.lang<c>, cir.sob = #cir.signed_overflow_behavior<undefined>, cir.triple = "x86_64-unknown-linux-gnu", dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<i64, dense<64> : vector<2xi64>>, #dlti.dl_entry<i128, dense<128> : vector<2xi64>>, #dlti.dl_entry<f128, dense<128> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr<270>, dense<32> : vector<4xi64>>, #dlti.dl_entry<f64, dense<64> : vector<2xi64>>, #dlti.dl_entry<f16, dense<16> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr<271>, dense<32> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<272>, dense<64> : vector<4xi64>>, #dlti.dl_entry<i16, dense<16> : vector<2xi64>>, #dlti.dl_entry<i8, dense<8> : vector<2xi64>>, #dlti.dl_entry<i32, dense<32> : vector<2xi64>>, #dlti.dl_entry<f80, dense<128> : vector<2xi64>>, #dlti.dl_entry<i1, dense<8> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi64>>, #dlti.dl_entry<"dlti.endianness", "little">, #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>>, llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"} {
  cir.func no_proto @foo() extra(#fn_attr) {
    cir.scope {
      %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["a", init] {alignment = 4 : i64} loc(#loc15)
      %1 = cir.const #cir.int<0> : !s32i loc(#loc6)
      cir.store %1, %0 : !s32i, !cir.ptr<!s32i> loc(#loc15)
      cir.for : cond {
        %2 = cir.load %0 : !cir.ptr<!s32i>, !s32i loc(#loc7)
        %3 = cir.const #cir.int<2> : !s32i loc(#loc8)
        %4 = cir.cmp(lt, %2, %3) : !s32i, !s32i loc(#loc16)
        %5 = cir.cast(int_to_bool, %4 : !s32i), !cir.bool loc(#loc9)
        cir.condition(%5) loc(#loc9)
      } body {
        cir.scope {
        } loc(#loc17)
        cir.yield loc(#loc4)
      } step {
        %2 = cir.load %0 : !cir.ptr<!s32i>, !s32i loc(#loc11)
        %3 = cir.unary(inc, %2) : !s32i, !s32i loc(#loc12)
        cir.store %3, %0 : !s32i, !cir.ptr<!s32i> loc(#loc18)
        cir.yield loc(#loc14)
      } loc(#loc14)
    } loc(#loc14)
    cir.return loc(#loc2)
  } loc(#loc13)
} loc(#loc)
#loc = loc("/home/wenhu/clangir/build/Release/bin/for.c":0:0)
#loc1 = loc("for.c":1:1)
#loc2 = loc("for.c":4:1)
#loc3 = loc("for.c":2:2)
#loc4 = loc("for.c":3:3)
#loc5 = loc("for.c":2:7)
#loc6 = loc("for.c":2:15)
#loc7 = loc("for.c":2:18)
#loc8 = loc("for.c":2:22)
#loc9 = loc("for.c":2:20)
#loc10 = loc("for.c":2:30)
#loc11 = loc("for.c":2:26)
#loc12 = loc("for.c":2:25)
#loc13 = loc(fused[#loc1, #loc2])
#loc14 = loc(fused[#loc3, #loc4])
#loc15 = loc(fused[#loc5, #loc6])
#loc16 = loc(fused[#loc7, #loc8])
#loc17 = loc(fused[#loc10, #loc4])
#loc18 = loc(fused[#loc12, #loc11])



  1. After, I use cir-opt to get mlir file, but not work.
    cir-opt -cir-to-mlir for.cir -o for.mlir

the error information:

for.c:2:22: error: failed to legalize unresolved materialization from '!cir.int<s, 32>' to 'i32' that remained live after conversion
        for (int a = 0; a < 2; a++) {
                            ^
for.c:2:22: note: see current operation: %7 = "builtin.unrealized_conversion_cast"(%6) : (!cir.int<s, 32>) -> i32
for.c:2:2: note: see existing live user here: 
"scf.for"(%2, %7, %4) ({
^bb0(%arg0: i32):
  "scf.yield"() : () -> ()
  "cir.scope"() ({
  }) : () -> ()
  "scf.yield"() : () -> ()
  "cir.yield"() : () -> ()
}) : (i32, i32, i32) -> ()
        for (int a = 0; a < 2; a++) {
        ^

What is the meaning of that?

  1. But if I use this command, i get mlir file successfully.
    clang -cc1 -triple x86_64-unknown-linux-gnu -fclangir -fno-clangir-direct-lowering -emit-mlir for.c -o for.mlir

for.mlir is here

module @"/home/wenhu/clangir/build/Release/bin/for.c" attributes {cir.lang = #cir.lang<c>, cir.sob = #cir.signed_overflow_behavior<undefined>, cir.triple = "x86_64-unknown-linux-gnu", dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<f64, dense<64> : vector<2xi64>>, #dlti.dl_entry<f128, dense<128> : vector<2xi64>>, #dlti.dl_entry<f16, dense<16> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr<270>, dense<32> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<272>, dense<64> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<271>, dense<32> : vector<4xi64>>, #dlti.dl_entry<i16, dense<16> : vector<2xi64>>, #dlti.dl_entry<i8, dense<8> : vector<2xi64>>, #dlti.dl_entry<i32, dense<32> : vector<2xi64>>, #dlti.dl_entry<f80, dense<128> : vector<2xi64>>, #dlti.dl_entry<i1, dense<8> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi64>>, #dlti.dl_entry<i64, dense<64> : vector<2xi64>>, #dlti.dl_entry<i128, dense<128> : vector<2xi64>>, #dlti.dl_entry<"dlti.endianness", "little">, #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>>, llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"} {
  func.func @foo() {
    memref.alloca_scope  {
      %alloca = memref.alloca() {alignment = 4 : i64} : memref<i32> loc(#loc11)
      %c0_i32 = arith.constant 0 : i32 loc(#loc6)
      memref.store %c0_i32, %alloca[] : memref<i32> loc(#loc11)
      %c2_i32 = arith.constant 2 : i32 loc(#loc7)
      %c1_i32 = arith.constant 1 : i32 loc(#loc10)
      scf.for %arg0 = %c0_i32 to %c2_i32 step %c1_i32  : i32 {
        memref.alloca_scope  {
        } loc(#loc12)
      } loc(#loc10)
    } loc(#loc10)
    return loc(#loc2)
  } loc(#loc9)
} loc(#loc)
#loc = loc("/home/wenhu/clangir/build/Release/bin/for.c":0:0)
#loc1 = loc("for.c":1:1)
#loc2 = loc("for.c":4:1)
#loc3 = loc("for.c":2:2)
#loc4 = loc("for.c":3:3)
#loc5 = loc("for.c":2:7)
#loc6 = loc("for.c":2:15)
#loc7 = loc("for.c":2:22)
#loc8 = loc("for.c":2:30)
#loc9 = loc(fused[#loc1, #loc2])
#loc10 = loc(fused[#loc3, #loc4])
#loc11 = loc(fused[#loc5, #loc6])
#loc12 = loc(fused[#loc8, #loc4])



The second measure can get mlir directly without cir file, why this command work well but the first measure not work?

bcardosolopes commented 3 weeks ago

@ShivaChen @GaoXiangYa

ShivaChen commented 3 weeks ago

The failure might be caused by the upper bound constant didn't be hoisted out of the loop. SCF loop required the loop upper bound as an input operand. So we have -cir-mlir-scf-prepare pass to hoist the boundary value. cir-opt usage might need to add the pass in the command line.

wenhu1024 commented 3 weeks ago

Thanks a lot, the command line works now.

cir-opt   -cir-mlir-scf-prepare  -cir-to-mlir for.cir -o for.mlir
bcardosolopes commented 2 weeks ago

Looks like issue is solved, closing