How to pass a pointer from my c++ code to mlir? (original) (raw)
April 24, 2024, 11:03am 1
Hi, I have a question about pointer in mlir: How to I pass a pointer from my c++ code to mlir ?
Suppose I have a class A in my c++code, and a function that take void* ptr
as parameter which is actually an A*
. I want to call the function from mlir.
I have defined a PtrType in my dialect to wrap the pointer of A, and want to call the function from llvm.
class A {
int64_t a;
};
extern "C" {
int64_t my_func(void * p);
}
struct PtrTypeStorage: public TypeStorage {
void* ptr = nullptr;
....
};
class PtrType: public mlir::Type::TypeBase<PtrType, mlir::Type, detail::PtrTypeStorage> {
public:
using Base::Base;
static PtrType get(mlir::MLIRContext* ctx);
size_t getNumElementTypes() { return 1; }
void setPtr(void* ptr);
static llvm::StringRef name;
};
And I have an op in dialect which just return a PtrType
:
def GetPtrOp : Toy_Op<"get_ptr"> {
let summary = "get_ptr";
let arguments = (ins);
let results = (outs Toy_PtrType:$output);
let assemblyFormat = "`(` `)` attr-dict `to` type($output)";
let builders = [
OpBuilder<(ins)>
];
}
I tried the following in lowering to llvm, but it does’t work
struct GetPtrOpLowering : public OpConversionPattern<mlir::toy::GetPtrOp> {
using OpConversionPattern<mlir::toy::GetPtrOp>::OpConversionPattern;
LogicalResult matchAndRewrite(mlir::toy::GetPtrOp op,
OpAdaptor adaptor,
ConversionPatternRewriter& rewriter) const override {
ModuleOp parentModule = op.getOperation()->getParentOfType<ModuleOp>();
auto* context = parentModule.getContext();
auto loc = op.getOperation()->getLoc();
auto ptrType = LLVM::LLVMPointerType::get(parentModule.getContext());
Value one = rewriter.create<LLVM::ConstantOp>(loc, rewriter.getI64Type(), rewriter.getIndexAttr(1));
Value allocated = rewriter.create<LLVM::AllocaOp>(loc, ptrType, PtrType::get(context), one);
mlir::Value res = rewriter.create<LLVM::LoadOp>(loc, PtrType::get(context), allocated);
rewriter.eraseOp(op);
return mlir::success();
}
};
When I run the code var a = get_ptr()
, the error says:
loc("codegen.toy":15:15): error: 'llvm.load' op result #0 must be LLVM type with size, but got '!toy.PtrType'
So I have the following questions:
- How do I convert the
PtrType
in my dialect toLLVM::LLVMPointerType
? - According the document of
Type
, everyType
is just a wrapper of an actualTypeStorage
. So What is the actual storageLLVM::LLVMPointerType
? Can I just get the actual storage and just set the pointer value ? I grep all code under llvm-project, and found thatLLVM::LLVMPointerType::get(context)
seems to be the only way to construct aLLVM::LLVMPointerType
. - If I use
MemrefType
, still I need to provide atype
, which also need to be converted to llvm type at last, back to the first question: how to convertvoid*
pointer toLLVM::LLVMPointerType
? - My goal is to call the function
my_func
with some object in my c++ code, Is my idea correct ? Are there any other idea to achieve this?
ftynse April 24, 2024, 4:36pm 2
This constructs invalid IR. Operations from the LLVM dialect accept only process values of LLVM dialect types or compatible builtin types. This is intentional. You cannot make LLVM dialect process your custom types.
This is the consequence of the above.
This depends on the semantics of your type. If they are identical to the LLVM pointer type, you have to replace all operations that operate on your type with corresponding operations that operate on the LLVM pointer type. You should also update block signatures. Check out the documentation: Dialect Conversion - MLIR
These seem to stem from a fundamental misunderstanding. The internal storage of types in a compiler has nothing to do with what that type can store when the compiled program runs. It is impossible to “set a value” of something in your program by modifying the code of the compiler and vice versa (disregarding exotic JIT scenarios).
That being said, you can define a function in the IR that takes an argument of !llvm.ptr
type. That function will be callable with any C pointer under all ABIs I’m aware of.
Hi, thanks for the reply. It seems that I confused with the compiler code and the running program. The pointer I need is just a void *
pointer, I will handle it in my c++ function later. So LLVM pointer should be enough. So I think I should define a function that takes an argument of !llvm.ptr
type.
The Toy
dialect has a GenericCallOp
, whose arguments are Variadic<Toy_Type>
. Can I add LLVM_AnyPointer
to Toy_Type
to support ptr type ? Or are there any other things need to do ? The type used directly in Toy
, such as F64Tensor
, seems to be slightly different from LLVM_AnyPointer
. LLVM_AnyPointer
is defined in another dialect llvm
, while F64Tensor
is defined in `CommonTypeConstraints.td’.
I tried to add LLVM_AnyPointer
directly in the td
file (actually the toy/Ops.td
file
in toy tutorial Ch7), but encountered an error.
include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
def Toy_Type : AnyTypeOf<[F64Tensor, I64, Toy_StructType, LLVM_AnyPointer]>;
The erros says
when more than 1 dialect is present, one must be selected via '-dialect'
Seems that use more than 1 dialects need to set some flags. I tried pass -dialect toy
to ninja
, but it didnt work. How can I fix this error? Thanks for any suggestions.
ftynse April 25, 2024, 10:29am 4
This will let the operation accept the type. But I suspect the lowering of that operation to the LLVM dialect may still need to be updated.
This is a flag for mlir-tblgen
that gets called by this cmake rule: llvm-project/mlir/examples/toy/Ch7/include/toy/CMakeLists.txt at main · llvm/llvm-project · GitHub if I’m not mistaken.
Hi, thanks for the reply. I finally succeed to build after add -dialect=toy
in the CmakeLists.txt
:
mlir_tablegen(Ops.h.inc -gen-op-decls -dialect=toy)
mlir_tablegen(Ops.cpp.inc -gen-op-defs -dialect=toy)
I’ll try to pass a pointer from my c++ code to the function defined in IR.