I’m working on packing and emulating i1 in SPIR-V. I have a patch to work, it is not landed yet. ⚙ D99724 [mlir][StandardToSPIRV] Handle i1 case for lowering memref.load/store op
It basically treats i1 like i8. With the patch.
I can lower both i1 and i8 cases, and the IRs are identical.
func @load_i1(%arg0: memref<i1>) {
%0 = memref.load %arg0[] : memref<i1>
return
}
func @load_i8(%arg0: memref<i8>) {
%0 = memref.load %arg0[] : memref<i8>
return
}
to
module attributes {spv.target_env = #spv.target_env<#spv.vce<v1.0, [Int16, StorageBuffer16BitAccess, Shader], [SPV_KHR_storage_buffer_storage_class, SPV_KHR_16bit_storage]>, {}>} {
spv.func @load_i8(%arg0: !spv.ptr<!spv.struct<(!spv.array<1 x i32, stride=4> [0])>, StorageBuffer>) "None" {
%0 = spv.Constant 0 : i32
%1 = spv.Constant 4 : i32
%2 = spv.SDiv %0, %1 : i32
%3 = spv.AccessChain %arg0[%0, %2] : !spv.ptr<!spv.struct<(!spv.array<1 x i32, stride=4> [0])>, StorageBuffer>, i32, i32
%4 = spv.Load "StorageBuffer" %3 : i32
%5 = spv.Constant 4 : i32
%6 = spv.Constant 8 : i32
%7 = spv.UMod %0, %5 : i32
%8 = spv.IMul %7, %6 : i32
%9 = spv.ShiftRightArithmetic %4, %8 : i32, i32
%10 = spv.Constant 255 : i32
%11 = spv.BitwiseAnd %9, %10 : i32
%12 = spv.Constant 24 : i32
%13 = spv.ShiftLeftLogical %11, %12 : i32, i32
%14 = spv.ShiftRightArithmetic %13, %12 : i32, i32
spv.Return
}
}
They generate the identical IRs. However, I hit an issue when I returned the value.
module attributes {
spv.target_env = #spv.target_env<
#spv.vce<v1.0, [Int16, StorageBuffer16BitAccess, Shader],
[SPV_KHR_storage_buffer_storage_class, SPV_KHR_16bit_storage]>, {}>
} {
func @load_i8(%arg0: memref<i8>) -> i8 {
%0 = memref.load %arg0[] : memref<i8>
return %0 : i8
}
}
The above one can be lowered to SPIR-V, but the below one can not
module attributes {
spv.target_env = #spv.target_env<
#spv.vce<v1.0, [Int16, StorageBuffer16BitAccess, Shader],
[SPV_KHR_storage_buffer_storage_class, SPV_KHR_16bit_storage]>, {}>
} {
func @load_i1(%arg0: memref<i1>) -> i1 {
%0 = memref.load %arg0[] : memref<i1>
return %0 : i1
}
}
The i1 case only works if it does not have users.
I dumped operands[0]
in ReturnOpPattern
. i8 case showed the replaced op %15 = spv.ShiftRightArithmetic %14, %13 : i32, i32
, and i1 case showed the old one %16 = memref.load <<UNKNOWN SSA VALUE>>[] : memref<i1>
. It is weird because it said that the pattern applied successfully, but the users still get the old operand.
I also verified that i1 case and i8 case generate the same log with -debug
and they are all marked legal and success.
It looks like a memref.load
was created because the variable name is %16
. Are there more debugging tips? Is it a bug in dialect conversion?
To repro, run mlir-opt -convert-std-to-spirv a.mlir
full log for i1: gist:8a4494f337629299959b6e7d59a882f5 · GitHub
full log for i8: gist:56a8fcdd6a8eb25a743a71667754e6e4 · GitHub