Which pass is supposed to handle index type to integer conversion?

This might have been asked before. The problem is that I have uses of the index type in a loop, and after a few conversion passes I still have unrealized_conversion_cast between i64 and index and I’m not sure which pass is supposed to handle that.

Originally, I had a loop like


%c0 = arith.constant 0 : index 
%c2 = arith.constant 2 : index 
%51 = arith.index_cast %50 : i32 to index 
 scf.for %arg9 = %c0 to %51  {
      %114 = arith.subi %51, %c2 : index 
      %115 = arith.cmpi slt, %arg9, %114 : index 
     ...
}

After ArithToLLVMConversionPass I got:


scf.for %arg9 = %10 to %68  {
      %131 = builtin.unrealized_conversion_cast %arg9 : index to i64
      %132 = llvm.sub %67, %0 : i64 
      %133 = llvm.icmp "slt" %131, %132 : i64 
}

Then the unrealized_conversion_cast op persisted through various lowering passes such as ConvertSCFToCFPas, ConvertFuncToLLVMPass and could not be really reconciled. I wonder if I’m missing a different pass to lower it.

Thanks!

You need at least convert-scf-to-cf, convert-arith-to-llvm, convert-cf-to-llvm and convert-func-to-llvm. Note that these passes are considered test passes and are discouraged. Instead, one is expected to assemble the patterns themselves in one sweep or use -convert-to-llvm.

1 Like

Thanks for the suggest. I tried with -convert-to-llvm but still had unreconcilable unrealized_conversion_cast on the generated IR.

How would index type be lowered? Is supposed to be just replaced with int64?

I just figured out the type converter is supposed to handle the lowering of the index type. It’s likely in my case the type converter isn’t set up properly.

BTW, do you think the following pattern should be considered reconcilable?

%187 = builtin.unrealized_conversion_cast %186 : i32 to index
%188 = builtin.unrealized_conversion_cast %187 : index to i64

Look at the defining op of its operand and/or the uses of its result. One of those will be an operation that wasn’t lowered to LLVM IR in most cases.

No. It does not cancel out.

Hello, I try to reproduce your example,

func.func @example(%memref : memref<?xf32>) -> (memref<?xf32>) {
%c0 = arith.constant 0 : index 
%c1 = arith.constant 1 : index 
%c2 = arith.constant 2 : index 
%50 = arith.constant 8 : i32
%val = arith.constant 21.5 : f32
%51 = arith.index_cast %50 : i32 to index 
 scf.for %arg9 = %c0 to %51 step %c1 {
      %114 = arith.subi %51, %c2 : index 
      %115 = arith.subi %arg9, %114 : index 
      memref.store %val, %memref[%115] : memref<?xf32>
}
return %memref :  memref<?xf32>
}

Complete lowering to llvm dialect is achieved through the following pass pipeline.

  -convert-scf-to-cf -convert-arith-to-llvm -convert-memref-to-llvm   -convert-func-to-llvm  -reconcile-unrealized-casts

Attached link: Compiler Explorer
I hope it can give you some inspiration, best wishes~

1 Like

Thanks for the help here!

After some internal discussion we think that using index type isn’t always optimal in our case as some size optimizations can be done on the induction variable. Since the integer types (int32/int64) is also allowed as the IV type of a SCF loop and in our case the index type is mostly introduced by the SCF loop optimizer (in particular the loop unroller), we are thinking about generalizing the loop unroller to use integer types instead.

Historically, index was pervasively used for address computations and it is deeply ingrained into the restrictions of affine loops. Non-affine loops inherited that, but I see more and more projects using i32/i64 explicitly, so it sounds reasonable to extend transformations to support that. One important caveat to think through is how to make sure overflow behavior is handled “reasonably”.

2 Likes

[mlir][scf] Allow unrolling loops with integer-typed IV. by htyu · Pull Request #106164 · llvm/llvm-project · GitHub as first attempt. I’m only changing the loop unroller as that’s the one being used and I verified the fix worked.

As far as overflow behavior is concerned, I think our frontend (actually the Triton compiler) handles that, by using the right integer type for the IV.

I have a similar issue where, when executing --convert-arith-to-emitc, there is a situation of mutual conversion between index and !emitc.size_t. It seems that this problem did not occur in previous versions.