Not understanding why I am getting "failed to legalize operation 'builtin.unrealized_conversion_cast' that was explicitly marked illegal"

Hi I am a beginner and I am struggling to understand the following error:

ukernel.mlir:25:5: error: failed to legalize operation 'builtin.unrealized_conversion_cast' that was explicitly marked illegal
    %cmem: memref<1xvector<12x32xf32>>
    ^
ukernel.mlir:25:5: note: see current operation: %20 = "builtin.unrealized_conversion_cast"(%19) : (!llvm.struct<(ptr<array<12 x vector<32xf32>>>, ptr<array<12 x vector<32xf32>>>, i64, array<1 x i64>, array<1 x i64>)>) -> memref<1xvector<12x32xf32>>

The error comes from the following code snippet:

func.func @vec_op_acc(
    %amem: memref<256xvector<12xf32>>, %bmem: memref<256xvector<32xf32>>,
    %cmem: memref<1xvector<12x32xf32>>
)
{
    %i0 = arith.constant 0 : index

    affine.for %k = 0 to 256 {
        %a = vector.load %amem[%k] : memref<256xvector<12xf32>>, vector<12xf32>
        %b = vector.load %bmem[%k] : memref<256xvector<32xf32>>, vector<32xf32>
        %c = vector.load %cmem[%i0] : memref<1xvector<12x32xf32>>, vector<12x32xf32>
        %res = vector.outerproduct %a, %b, %c : vector<12xf32>, vector<32xf32>
        vector.store %res, %cmem[%i0] : memref<1xvector<12x32xf32>>, vector<12x32xf32>
    }

    return
}

I am using mlir-opt -pass-pipeline="convert-vector-to-llvm,convert-memref-to-llvm,convert-func-to-llvm,reconcile-unrealized-casts" ukernel.mlir > lowered/ukernel.lowered.mlir to lower the snippet to llvm MLIR.

Any insight would be greatly appreciated.

Thank you and apologies if this is a dumb question!

It generally means the type conversion wasn’t completed by some previous passes. Remove the reconcile-unrealized-casts to see the IR and look for unrealized_conversion_cast operations that are not paired with the casts going into the other direction.

Looking at your pass pipeline, it is missing at least lower-affine, convert-scf-to-cf, convert-cf-to-llvm. I also don’t know which version you are at because MLIR at HEAD no longer has convert-memref-to-llvm.

Thank you for your reply!

I removed unrealied_conversion_cast and found that there is a vector.load that is not being lowered correctly.

    %43 = vector.load %20[%27] : memref<1xvector<12x32xf32>>, vector<12x32xf32>
    %44 = builtin.unrealized_conversion_cast %43 : vector<12x32xf32> to !llvm.array<12 x vector<32xf32>>

However, I am unsure of how to get it to lower properly. Maybe this is due to me not using the most recent MLIR commit. I will try to update my LLVM repo and rebuild to see if anything changes.

In any case, does the code make sense? Do you think there might be a better way to express it in another dialect? In general, I am looking to generate code that will perform a sum of outer products using SIMD instructions (FMA specifically). I am doing this to see if the code that is being generated is efficiently utilizing the FMA units on my machine.

Note: this is similar to the work done by Uday Bondhugula.

The issue is unlikely to just magically go away with a version bump :wink: Given that the memref already contains the vector type, it is possible to use memref.load/store here, vector.load/store is mostly intended from loading a vector from a memref of scalars. This will save one lowering steps like vector operation unrolling.

After that change, the code lowers to llvm with -lower-affine -convert-scf-to-cf -memref-expand -finalize-memref-to-llvm -convert-vector-to-llvm -convert-func-to-llvm -convert-cf-to-llvm -reconcile-unrealized-casts producing fmuladd intrinsics in my case.

1 Like

It works!! Thank you very much for your help :slight_smile: