Assert in Mem2Reg.cpp due to pointer address space mismatch
func @_ZN2cl4sycl6detail7declptrINS0_4itemILi2ELb1EEEEEPT_v() -> !llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>> attributes {llvm.linkage = #llvm.linkage<linkonce_odr>} {
%false = arith.constant false
%true = arith.constant true
%0 = memref.alloca() : memref<i1>
memref.store %true, %0[] : memref<i1>
%1 = memref.alloca() : memref<!llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>>>
%2 = memref.load %0[] : memref<i1>
%3 = memref.load %1[] : memref<!llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>>>
%4:2 = scf.if %true -> (i1, !llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>, 4>) {
%6 = memref.load %0[] : memref<i1>
%7:2 = scf.if %true -> (i1, !llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>, 4>) {
%8 = llvm.mlir.null : !llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>, 4>
memref.store %8, %1[] : memref<!llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>>>
memref.store %false, %0[] : memref<i1>
scf.yield %false, %8 : i1, !llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>, 4>
} else {
scf.yield %true, %3 : i1, !llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>>
}
scf.yield %7#0, %7#1 : i1, !llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>, 4>
} else {
scf.yield %true, %3 : i1, !llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>>
}
%5 = memref.load %1[] : memref<!llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>>>
return %5 : !llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>>
}
The above MLIR representation is related to below code, dumped at the entry to the first call to Mem2Reg pass.
template <typename T> T *declptr() { return static_cast<T *>(nullptr); }
processing the function using Mem2Reg results in below assert.
!llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>> - !llvm.ptr<struct<(struct<(struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>, struct<(struct<(array<2 x i64>)>)>)>)>, 4>
mlir-clang: /home/m/Polygeist/lib/polygeist/Passes/Mem2Reg.cpp:641: {anonymous}::Mem2Reg::forwardStoreToLoad(mlir::Value, std::vector<long int, std::allocator<long int> >, llvm::SmallVectorImpl<mlir::Operation*>&)::<lambda(mlir::Block&, mlir::Value)>: Assertion `loadOp.getType() == lastVal.getType() && "mismatched load type"' failed.
The assert is related to mismatch between the address space of the pointer types in lastVal.getType() and loadType.getType.
Processing above as a stand alone C++ function does not result in the above assert. The assert is due to the pointer type being cached with address space of 4 in CodegenTypes::ConvertTypes while processing an earlier function.
To handle the assert above I considering 2 possible approaches:
-
To limit the comparison to ElementType of the pointers and ignore the Address space of the pointer types. Something like below: Check equality and assert on loadOp.getType()->getElementType() == lastVal.getType()->getElementType().
-
We could also consider applying the optimisation only when pointers at both load / store share similar address space.
I would appreciate any suggestions on above potential solutions or any other viable solution.
Regards, Moadeli
So the issue is that the input code to the pass is valid. Namely, the element type of the memref must be equivalent to the values stored. This obviously matters for this pass, but would also matter for others.
Is there a way beforehand you could ensure the mlir is valid (say doing a cast of the address space before load/store)?