I’m trying to write a lowering pass that converts an op returning a single value to multiple ops. The result of the original op will need to be replaced by all the new values.
Notice that the operation “foo” with custom type “MultipleIntegersType” got lowered to multiple ops.
I wrote a custom type conversion:
typeConverter.addConversion(
[](MultipleIntegersType t, SmallVectorImpl<Type>& result) -> llvm::Optional<LogicalResult> {
// omitted: place correct number of integers into result here
return success();
});
Also in pseudo-code, here is how I wrote the lowering pattern for foo:
auto intOne = rewriter.create<IntegerOp>(...);
auto intTwo = rewriter.create<IntegerOp>(...);
rewriter.replaceOp(originalOp, ValueRange{intOne, intTwo});
However, this doesn’t seem to work: I always get some variation of “wrong number of results” on the rewriter.replaceOp line. This seems counter-intuitive to me - why hasn’t the type converter been applied, which would result in the result type being multiple integers?
Is there any way to achieve what I want? I realise I could just pack the values into a struct and lower the MultipleIntegersType into a single struct, but I’d like to avoid that if possible.
There is currently no support for one-to-many value replacement in the dialect conversion infrastructure.
Only partial support is available in block argument conversion, where it is supported by the type converter providing a way to pack multiple values back into one:
This mechanism could be potentially extended to op results, but that would likely require breaking API changes and will take time.
In the meantime, you can introduce packing and extraction ops for your types in the conversion process, and then canonicalize them away in a separate step by replacing
(1) Is there easier way to do one-to-many replacement now in 2023? Since this problem was answered in 2021.
(2) It seems that vector::InsertElementOp and vector::ExtractElementOp are designed for this situation. But how can I define an initial vector value before I insert elements into it? I noticed that for LLVM::InsertElementOp and LLVM::ExtractElementOp, there is a op called llvm.undef, which intializes a vector value or a struct value. What is the “undef” op for vector::InsertElementOp and vector::ExtractElementOp?