16#include "mlir/Dialect/Affine/IR/AffineOps.h"
17#include "mlir/Dialect/Arith/IR/Arith.h"
18#include "mlir/Dialect/MemRef/IR/MemRef.h"
19#include "mlir/Dialect/Vector/IR/VectorOps.h"
20#include "mlir/IR/PatternMatch.h"
21#include "mlir/Pass/Pass.h"
22#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
23#include "llvm/ADT/Sequence.h"
25#define DEBUG_TYPE "aievec-split-load-ups-chains"
51 LogicalResult matchAndRewrite(UPSOp upsOp,
52 PatternRewriter &rewriter)
const override {
54 Value source = upsOp.getSource();
55 auto srcVecTy = dyn_cast<VectorType>(source.getType());
60 auto resultVecTy = dyn_cast<VectorType>(upsOp.getResult().getType());
65 Type srcElemTy = srcVecTy.getElementType();
66 Type resultElemTy = resultVecTy.getElementType();
68 if (!srcElemTy.isInteger() || !resultElemTy.isInteger())
71 unsigned srcBitWidth = srcElemTy.getIntOrFloatBitWidth();
72 unsigned resultBitWidth = resultElemTy.getIntOrFloatBitWidth();
73 int64_t srcLanes = srcVecTy.getNumElements();
74 int64_t resultLanes = resultVecTy.getNumElements();
76 int64_t srcVectorSize = srcBitWidth * srcLanes;
77 int64_t resultVectorSize = resultBitWidth * resultLanes;
81 if (srcVectorSize != 1024 || resultVectorSize != 2048)
85 if (resultBitWidth != 32 || srcBitWidth != 16)
89 auto loadOp = source.getDefiningOp<vector::LoadOp>();
94 if (!loadOp.getResult().hasOneUse())
97 Location loc = upsOp.getLoc();
100 Value memRef = loadOp.getBase();
101 ValueRange indices = loadOp.getIndices();
104 int64_t halfLanes = srcLanes / 2;
105 auto halfSrcVecTy = VectorType::get({halfLanes}, srcElemTy);
106 auto halfResultVecTy = VectorType::get({halfLanes}, resultElemTy);
110 int64_t elementOffset = halfLanes;
113 SmallVector<Value> firstHalfIndices(indices.begin(), indices.end());
116 SmallVector<Value> secondHalfIndices(indices.begin(), indices.end());
119 if (!indices.empty()) {
120 Value lastIdx = indices.back();
122 arith::ConstantIndexOp::create(rewriter, loc, elementOffset);
124 arith::AddIOp::create(rewriter, loc, lastIdx, offsetVal);
125 secondHalfIndices.back() = newLastIdx;
129 auto loadHalf0 = vector::LoadOp::create(rewriter, loc, halfSrcVecTy, memRef,
133 auto loadHalf1 = vector::LoadOp::create(rewriter, loc, halfSrcVecTy, memRef,
137 auto upsHalf0 = UPSOp::create(rewriter, loc, halfResultVecTy,
138 loadHalf0.getResult(), upsOp.getShift());
141 auto upsHalf1 = UPSOp::create(rewriter, loc, halfResultVecTy,
142 loadHalf1.getResult(), upsOp.getShift());
146 SmallVector<int64_t> concatMask;
147 for (int64_t i = 0; i < resultLanes; ++i) {
148 concatMask.push_back(i);
151 auto concatOp = vector::ShuffleOp::create(
152 rewriter, loc, upsHalf0.getResult(), upsHalf1.getResult(), concatMask);
155 rewriter.replaceOp(upsOp, concatOp.getResult());
180struct SplitVectorSrsStoreChainPattern
184 LogicalResult matchAndRewrite(vector::StoreOp storeOp,
185 PatternRewriter &rewriter)
const override {
187 Value valueToStore = storeOp.getValueToStore();
188 auto storeVecTy = dyn_cast<VectorType>(valueToStore.getType());
193 auto srsOp = valueToStore.getDefiningOp<SRSOp>();
198 if (!srsOp.getResult().hasOneUse())
202 Value srsSource = srsOp.getSource();
203 auto srcVecTy = dyn_cast<VectorType>(srsSource.getType());
207 Type srcElemTy = srcVecTy.getElementType();
208 Type resultElemTy = storeVecTy.getElementType();
210 if (!srcElemTy.isInteger() || !resultElemTy.isInteger())
213 unsigned srcBitWidth = srcElemTy.getIntOrFloatBitWidth();
214 unsigned resultBitWidth = resultElemTy.getIntOrFloatBitWidth();
215 int64_t srcLanes = srcVecTy.getNumElements();
216 int64_t resultLanes = storeVecTy.getNumElements();
218 int64_t srcVectorSize = srcBitWidth * srcLanes;
219 int64_t resultVectorSize = resultBitWidth * resultLanes;
223 if (srcVectorSize != 2048 || resultVectorSize != 1024)
227 if (srcBitWidth != 32 || resultBitWidth != 16)
230 Location loc = storeOp.getLoc();
233 Value memRef = storeOp.getBase();
234 ValueRange indices = storeOp.getIndices();
237 int64_t halfSrcLanes = srcLanes / 2;
238 int64_t halfResultLanes = resultLanes / 2;
239 auto halfResultVecTy = VectorType::get({halfResultLanes}, resultElemTy);
242 SmallVector<int64_t> firstHalfMask, secondHalfMask;
243 for (int64_t i = 0; i < halfSrcLanes; ++i) {
244 firstHalfMask.push_back(i);
245 secondHalfMask.push_back(halfSrcLanes + i);
248 auto srcHalf0 = vector::ShuffleOp::create(rewriter, loc, srsSource,
249 srsSource, firstHalfMask);
250 auto srcHalf1 = vector::ShuffleOp::create(rewriter, loc, srsSource,
251 srsSource, secondHalfMask);
254 auto srsHalf0 = SRSOp::create(rewriter, loc, halfResultVecTy,
255 srcHalf0.getResult(), srsOp.getShift());
258 auto srsHalf1 = SRSOp::create(rewriter, loc, halfResultVecTy,
259 srcHalf1.getResult(), srsOp.getShift());
262 int64_t elementOffset = halfResultLanes;
265 SmallVector<Value> firstHalfIndices(indices.begin(), indices.end());
268 SmallVector<Value> secondHalfIndices(indices.begin(), indices.end());
271 if (!indices.empty()) {
272 Value lastIdx = indices.back();
274 arith::ConstantIndexOp::create(rewriter, loc, elementOffset);
276 arith::AddIOp::create(rewriter, loc, lastIdx, offsetVal);
277 secondHalfIndices.back() = newLastIdx;
281 vector::StoreOp::create(rewriter, loc, srsHalf0.getResult(), memRef,
285 vector::StoreOp::create(rewriter, loc, srsHalf1.getResult(), memRef,
289 rewriter.eraseOp(storeOp);
306struct SplitVectorLoadMatMulLhsPattern
310 LogicalResult matchAndRewrite(vector::LoadOp loadOp,
311 PatternRewriter &rewriter)
const override {
312 VectorType loadTy = loadOp.getVectorType();
313 if (loadTy.getRank() != 1 || loadTy.getNumElements() != 64 ||
314 !loadTy.getElementType().isBF16())
317 auto bf16Tile = VectorType::get({8, 8}, rewriter.getBF16Type());
318 auto f32Tile = VectorType::get({8, 8}, rewriter.getF32Type());
319 auto feedsOnlyMatMulLhs = [&](Operation *user) {
320 auto cast = dyn_cast<vector::ShapeCastOp>(user);
321 if (!cast || cast.getResultVectorType() != bf16Tile)
323 return llvm::all_of(cast->getUses(), [&](OpOperand &use) {
324 auto matmul = dyn_cast<MatMulOp_AIE2P>(use.getOwner());
325 return matmul && use.getOperandNumber() == 0 &&
326 matmul.getRhs().getType() == bf16Tile &&
327 matmul.getAcc().getType() == f32Tile;
330 if (loadOp->use_empty() ||
331 !llvm::all_of(loadOp->getUsers(), feedsOnlyMatMulLhs))
334 Location loc = loadOp.getLoc();
335 auto halfTy = VectorType::get({32}, rewriter.getBF16Type());
336 SmallVector<Value> hiIndices(loadOp.getIndices());
337 Value c32 = arith::ConstantIndexOp::create(rewriter, loc, 32);
339 arith::AddIOp::create(rewriter, loc, hiIndices.back(), c32);
340 Value lo = vector::LoadOp::create(rewriter, loc, halfTy, loadOp.getBase(),
341 loadOp.getIndices());
342 Value hi = vector::LoadOp::create(rewriter, loc, halfTy, loadOp.getBase(),
344 SmallVector<int64_t> concatMask =
345 llvm::to_vector(llvm::seq<int64_t>(0, 64));
346 rewriter.replaceOpWithNewOp<vector::ShuffleOp>(loadOp, lo, hi, concatMask);
352struct SplitVectorLoadUpsChainsPass
353 :
public PassWrapper<SplitVectorLoadUpsChainsPass, OperationPass<>> {
354 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(SplitVectorLoadUpsChainsPass)
356 StringRef getArgument()
const final {
return "aievec-split-load-ups-chains"; }
358 StringRef getDescription()
const final {
359 return "Split 1024-bit vector loads and stores whose halves are widened "
360 "or narrowed separately";
363 void getDependentDialects(DialectRegistry ®istry)
const override {
364 registry.insert<vector::VectorDialect, arith::ArithDialect,
365 memref::MemRefDialect, affine::AffineDialect,
366 xilinx::aievec::AIEVecDialect>();
369 void runOnOperation()
override {
370 Operation *op = getOperation();
371 MLIRContext *context = &getContext();
372 RewritePatternSet patterns(context);
375 .add<SplitVectorLoadUpsChainPattern, SplitVectorSrsStoreChainPattern,
376 SplitVectorLoadMatMulLhsPattern>(context);
378 if (failed(applyPatternsGreedily(op, std::move(patterns)))) {
390 return std::make_unique<SplitVectorLoadUpsChainsPass>();
std::unique_ptr<::mlir::Pass > createSplitVectorLoadUpsChainsPass()
Create a pass that splits vector.load + aievec.ups chains to reduce shuffle operations for AIE2p targ...