Skip to content

Commit c2047ad

Browse files
committed
[mlir][VectorOps] Add conversion of 1-D vector.interleave ops to LLVM
The 1-D case directly maps to LLVM intrinsics. The n-D case will be handled by unrolling to 1-D first (in a later patch).
1 parent 4b442ee commit c2047ad

File tree

2 files changed

+77
-1
lines changed

2 files changed

+77
-1
lines changed

mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1734,6 +1734,44 @@ struct VectorSplatNdOpLowering : public ConvertOpToLLVMPattern<SplatOp> {
17341734
}
17351735
};
17361736

1737+
/// Conversion pattern for a `vector.interleave`.
1738+
/// This supports fixed-sized vectors and scalable vectors.
1739+
struct VectorInterleaveOpLowering
1740+
: public ConvertOpToLLVMPattern<vector::InterleaveOp> {
1741+
using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern;
1742+
1743+
LogicalResult
1744+
matchAndRewrite(vector::InterleaveOp interleaveOp, OpAdaptor adaptor,
1745+
ConversionPatternRewriter &rewriter) const override {
1746+
VectorType resultType = interleaveOp.getResultVectorType();
1747+
// n-D interleaves should have been lowered already.
1748+
if (resultType.getRank() != 1)
1749+
return failure();
1750+
// If the result is rank 1, then this directly maps to LLVM.
1751+
if (resultType.isScalable()) {
1752+
rewriter.replaceOpWithNewOp<LLVM::experimental_vector_interleave2>(
1753+
interleaveOp, typeConverter->convertType(resultType),
1754+
adaptor.getLhs(), adaptor.getRhs());
1755+
return success();
1756+
}
1757+
// Lower fixed-size interleaves to a shufflevector. While the
1758+
// vector.interleave2 intrinsic supports fixed and scalable vectors, the
1759+
// langref still recommends fixed-vectors use shufflevector, see:
1760+
// https://llvm.org/docs/LangRef.html#id876.
1761+
int64_t resultVectorSize = resultType.getNumElements();
1762+
SmallVector<int32_t> interleaveShuffleMask;
1763+
interleaveShuffleMask.reserve(resultVectorSize);
1764+
for (int i = 0, end = resultVectorSize / 2; i < end; ++i) {
1765+
interleaveShuffleMask.push_back(i);
1766+
interleaveShuffleMask.push_back((resultVectorSize / 2) + i);
1767+
}
1768+
rewriter.replaceOpWithNewOp<LLVM::ShuffleVectorOp>(
1769+
interleaveOp, adaptor.getLhs(), adaptor.getRhs(),
1770+
interleaveShuffleMask);
1771+
return success();
1772+
}
1773+
};
1774+
17371775
} // namespace
17381776

17391777
/// Populate the given list with patterns that convert from Vector to LLVM.
@@ -1758,7 +1796,8 @@ void mlir::populateVectorToLLVMConversionPatterns(
17581796
VectorExpandLoadOpConversion, VectorCompressStoreOpConversion,
17591797
VectorSplatOpLowering, VectorSplatNdOpLowering,
17601798
VectorScalableInsertOpLowering, VectorScalableExtractOpLowering,
1761-
MaskedReductionOpConversion>(converter);
1799+
MaskedReductionOpConversion, VectorInterleaveOpLowering>(
1800+
converter);
17621801
// Transfer ops with rank > 1 are handled by VectorToSCF.
17631802
populateVectorTransferLoweringPatterns(patterns, /*maxTransferRank=*/1);
17641803
}

mlir/test/Conversion/VectorToLLVM/vector-to-llvm.mlir

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2460,3 +2460,40 @@ func.func @make_fixed_vector_of_scalable_vector(%f : f64) -> vector<3x[2]xf64>
24602460
%res = vector.broadcast %f : f64 to vector<3x[2]xf64>
24612461
return %res : vector<3x[2]xf64>
24622462
}
2463+
2464+
// -----
2465+
2466+
// CHECK-LABEL: @vector_interleave_0d
2467+
// CHECK-SAME: %[[LHS:.*]]: vector<i8>, %[[RHS:.*]]: vector<i8>)
2468+
func.func @vector_interleave_0d(%a: vector<i8>, %b: vector<i8>) -> vector<2xi8> {
2469+
// CHECK: %[[LHS_RANK1:.*]] = builtin.unrealized_conversion_cast %[[LHS]] : vector<i8> to vector<1xi8>
2470+
// CHECK: %[[RHS_RANK1:.*]] = builtin.unrealized_conversion_cast %[[RHS]] : vector<i8> to vector<1xi8>
2471+
// CHECK: %[[ZIP:.*]] = llvm.shufflevector %[[LHS_RANK1]], %[[RHS_RANK1]] [0, 1] : vector<1xi8>
2472+
// CHECK: return %[[ZIP]]
2473+
%0 = vector.interleave %a, %b : vector<i8>
2474+
return %0 : vector<2xi8>
2475+
}
2476+
2477+
// -----
2478+
2479+
// CHECK-LABEL: @vector_interleave_1d
2480+
// CHECK-SAME: %[[LHS:.*]]: vector<8xf32>, %[[RHS:.*]]: vector<8xf32>)
2481+
func.func @vector_interleave_1d(%a: vector<8xf32>, %b: vector<8xf32>) -> vector<16xf32>
2482+
{
2483+
// CHECK: %[[ZIP:.*]] = llvm.shufflevector %[[LHS]], %[[RHS]] [0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15] : vector<8xf32>
2484+
// CHECK: return %[[ZIP]]
2485+
%0 = vector.interleave %a, %b : vector<8xf32>
2486+
return %0 : vector<16xf32>
2487+
}
2488+
2489+
// -----
2490+
2491+
// CHECK-LABEL: @vector_interleave_1d_scalable
2492+
// CHECK-SAME: %[[LHS:.*]]: vector<[4]xi32>, %[[RHS:.*]]: vector<[4]xi32>)
2493+
func.func @vector_interleave_1d_scalable(%a: vector<[4]xi32>, %b: vector<[4]xi32>) -> vector<[8]xi32>
2494+
{
2495+
// CHECK: %[[ZIP:.*]] = "llvm.intr.experimental.vector.interleave2"(%[[LHS]], %[[RHS]]) : (vector<[4]xi32>, vector<[4]xi32>) -> vector<[8]xi32>
2496+
// CHECK: return %[[ZIP]]
2497+
%0 = vector.interleave %a, %b : vector<[4]xi32>
2498+
return %0 : vector<[8]xi32>
2499+
}

0 commit comments

Comments
 (0)