42 unsigned vectorLength;
43 bool enableVLAVectorization;
44 bool enableSIMDIndex32;
48static bool isInvariantValue(
Value val,
Block *block) {
73static bool hasKnownNonUnitStride(
Value mem) {
85 if (toCoords.getLevel() >= cooStart)
90 auto memTp = dyn_cast<MemRefType>(mem.
getType());
95 if (
failed(memTp.getStridesAndOffset(strides, offset)))
97 return !strides.empty() && !ShapedType::isDynamic(strides.back()) &&
102static VectorType vectorType(VL vl,
Type etp) {
103 return VectorType::get(vl.vectorLength, etp, vl.enableVLAVectorization);
107static VectorType vectorType(VL vl,
Value mem) {
114 VectorType mtp = vectorType(vl, rewriter.
getI1Type());
119 IntegerAttr loInt, hiInt, stepInt;
123 if (((hiInt.getInt() - loInt.getInt()) % stepInt.getInt()) == 0) {
125 return vector::BroadcastOp::create(rewriter, loc, mtp, trueVal);
139 return vector::CreateMaskOp::create(rewriter, loc, mtp, end);
146 VectorType vtp = vectorType(vl, val.
getType());
147 return vector::BroadcastOp::create(rewriter, val.
getLoc(), vtp, val);
156 VectorType vtp = vectorType(vl, mem);
158 if (llvm::isa<VectorType>(idxs.back().getType())) {
160 Value indexVec = idxs.back();
162 return vector::GatherOp::create(rewriter, loc, vtp, mem, scalarArgs,
163 indexVec, vmask, pass);
165 return vector::MaskedLoadOp::create(rewriter, loc, vtp, mem, idxs, vmask,
175 if (llvm::isa<VectorType>(idxs.back().getType())) {
177 Value indexVec = idxs.back();
179 vector::ScatterOp::create(rewriter, loc,
nullptr, mem,
180 scalarArgs, indexVec, vmask,
rhs);
183 vector::MaskedStoreOp::create(rewriter, loc, mem, idxs, vmask,
rhs);
188static bool isVectorizableReduction(
Value red,
Value iter,
189 vector::CombiningKind &kind) {
191 kind = vector::CombiningKind::ADD;
192 return addf->getOperand(0) == iter || addf->getOperand(1) == iter;
195 kind = vector::CombiningKind::ADD;
196 return addi->getOperand(0) == iter || addi->getOperand(1) == iter;
199 kind = vector::CombiningKind::ADD;
200 return subf->getOperand(0) == iter;
203 kind = vector::CombiningKind::ADD;
204 return subi->getOperand(0) == iter;
207 kind = vector::CombiningKind::MUL;
208 return mulf->getOperand(0) == iter || mulf->getOperand(1) == iter;
211 kind = vector::CombiningKind::MUL;
212 return muli->getOperand(0) == iter || muli->getOperand(1) == iter;
215 kind = vector::CombiningKind::AND;
216 return andi->getOperand(0) == iter || andi->getOperand(1) == iter;
219 kind = vector::CombiningKind::OR;
220 return ori->getOperand(0) == iter || ori->getOperand(1) == iter;
223 kind = vector::CombiningKind::XOR;
224 return xori->getOperand(0) == iter || xori->getOperand(1) == iter;
237 vector::CombiningKind kind;
238 if (!isVectorizableReduction(red, iter, kind))
239 llvm_unreachable(
"unknown reduction");
241 case vector::CombiningKind::ADD:
242 case vector::CombiningKind::XOR:
244 return vector::InsertOp::create(rewriter, loc, r,
247 case vector::CombiningKind::MUL:
249 return vector::InsertOp::create(rewriter, loc, r,
252 case vector::CombiningKind::AND:
253 case vector::CombiningKind::OR:
255 return vector::BroadcastOp::create(rewriter, loc, vtp, r);
259 llvm_unreachable(
"unknown reduction kind");
281static bool vectorizeSubscripts(
PatternRewriter &rewriter, scf::ForOp forOp,
285 unsigned dim = subs.size();
287 for (
auto sub : subs) {
288 bool innermost = ++d == dim;
294 if (isInvariantValue(sub, block)) {
306 if (
auto arg = llvm::dyn_cast<BlockArgument>(sub)) {
307 if (isInvariantArg(arg, block) == innermost)
316 if (
auto icast = cast.getDefiningOp<arith::IndexCastOp>())
317 cast = icast->getOperand(0);
318 else if (
auto ecast = cast.getDefiningOp<arith::ExtUIOp>())
319 cast = ecast->getOperand(0);
336 if (
auto load = cast.getDefiningOp<memref::LoadOp>()) {
339 if (hasKnownNonUnitStride(
load.getMemRef()))
345 genVectorLoad(rewriter, loc, vl,
load.getMemRef(), idxs2, vmask);
346 Type etp = llvm::cast<VectorType>(vload.
getType()).getElementType();
347 if (!llvm::isa<IndexType>(etp)) {
349 vload = arith::ExtUIOp::create(
350 rewriter, loc, vectorType(vl, rewriter.
getI32Type()), vload);
352 vload = arith::ExtUIOp::create(
353 rewriter, loc, vectorType(vl, rewriter.
getI64Type()), vload);
355 idxs.push_back(vload);
362 if (
auto load = cast.getDefiningOp<arith::AddIOp>()) {
366 if (!isInvariantValue(inv, block)) {
368 idx =
load.getOperand(0);
371 if (isInvariantValue(inv, block)) {
372 if (
auto arg = llvm::dyn_cast<BlockArgument>(idx)) {
373 if (isInvariantArg(arg, block) || !innermost)
377 arith::AddIOp::create(rewriter, forOp.getLoc(), inv, idx));
388 if (isa<xxx>(def)) { \
390 vexp = xxx::create(rewriter, loc, vx); \
394#define TYPEDUNAOP(xxx) \
395 if (auto x = dyn_cast<xxx>(def)) { \
397 VectorType vtp = vectorType(vl, x.getType()); \
398 vexp = xxx::create(rewriter, loc, vtp, vx); \
404 if (isa<xxx>(def)) { \
406 vexp = xxx::create(rewriter, loc, vx, vy); \
416static bool vectorizeExpr(
PatternRewriter &rewriter, scf::ForOp forOp, VL vl,
420 if (!VectorType::isValidElementType(exp.
getType()))
423 if (
auto arg = llvm::dyn_cast<BlockArgument>(exp)) {
424 if (arg == forOp.getInductionVar()) {
428 VectorType vtp = vectorType(vl, arg.
getType());
429 Value veci = vector::BroadcastOp::create(rewriter, loc, vtp, arg);
430 Value incr = vector::StepOp::create(rewriter, loc, vtp);
431 vexp = arith::AddIOp::create(rewriter, loc, veci, incr);
439 vexp = genVectorInvariantValue(rewriter, vl, exp);
447 vexp = genVectorInvariantValue(rewriter, vl, exp);
456 if (
auto load = dyn_cast<memref::LoadOp>(def)) {
457 if (hasKnownNonUnitStride(
load.getMemRef()))
459 auto subs =
load.getIndices();
461 if (vectorizeSubscripts(rewriter, forOp, vl, subs, codegen, vmask, idxs)) {
463 vexp = genVectorLoad(rewriter, loc, vl,
load.getMemRef(), idxs, vmask);
477 if (vectorizeExpr(rewriter, forOp, vl, def->
getOperand(0), codegen, vmask,
504 if (vectorizeExpr(rewriter, forOp, vl, def->
getOperand(0), codegen, vmask,
506 vectorizeExpr(rewriter, forOp, vl, def->
getOperand(1), codegen, vmask,
512 if (isa<arith::ShLIOp>(def) || isa<arith::ShRUIOp>(def) ||
513 isa<arith::ShRSIOp>(def)) {
515 if (!isInvariantValue(shiftFactor, block))
522 BINOP(arith::DivSIOp)
523 BINOP(arith::DivUIOp)
532 BINOP(arith::ShRUIOp)
533 BINOP(arith::ShRSIOp)
548static bool vectorizeStmt(
PatternRewriter &rewriter, scf::ForOp forOp, VL vl,
559 scf::YieldOp yield = cast<scf::YieldOp>(block.
getTerminator());
560 auto &last = *++block.
rbegin();
574 if (vl.enableVLAVectorization) {
576 vector::VectorScaleOp::create(rewriter, loc, rewriter.
getIndexType());
577 step = arith::MulIOp::create(rewriter, loc, vscale, step);
579 if (!yield.getResults().empty()) {
580 Value init = forOp.getInitArgs()[0];
581 VectorType vtp = vectorType(vl, init.
getType());
582 Value vinit = genVectorReducInit(rewriter, loc, yield->getOperand(0),
583 forOp.getRegionIterArg(0), init, vtp);
585 scf::ForOp::create(rewriter, loc, forOp.getLowerBound(),
586 forOp.getUpperBound(), step, vinit,
587 nullptr, forOp.getUnsignedCmp());
596 vmask = genVectorMask(rewriter, loc, vl, forOp.getInductionVar(),
597 forOp.getLowerBound(), forOp.getUpperBound(), step);
602 if (!yield.getResults().empty()) {
604 if (yield->getNumOperands() != 1)
606 Value red = yield->getOperand(0);
607 Value iter = forOp.getRegionIterArg(0);
608 vector::CombiningKind kind;
610 if (isVectorizableReduction(red, iter, kind) &&
611 vectorizeExpr(rewriter, forOp, vl, red, codegen, vmask, vrhs)) {
613 Value partial = forOpNew.getResult(0);
614 Value vpass = genVectorInvariantValue(rewriter, vl, iter);
615 Value vred = arith::SelectOp::create(rewriter, loc, vmask, vrhs, vpass);
616 scf::YieldOp::create(rewriter, loc, vred);
618 Value vres = vector::ReductionOp::create(rewriter, loc, kind, partial);
624 forOpNew.getInductionVar());
626 forOpNew.getRegionIterArg(0));
631 }
else if (
auto store = dyn_cast<memref::StoreOp>(last)) {
633 if (hasKnownNonUnitStride(store.getMemRef()))
635 auto subs = store.getIndices();
639 if (vectorizeSubscripts(rewriter, forOp, vl, subs, codegen, vmask, idxs) &&
640 vectorizeExpr(rewriter, forOp, vl,
rhs, codegen, vmask, vrhs)) {
642 genVectorStore(rewriter, loc, store.getMemRef(), idxs, vmask, vrhs);
649 assert(!codegen &&
"cannot call codegen when analysis failed");
656 using OpRewritePattern<scf::ForOp>::OpRewritePattern;
658 ForOpRewriter(MLIRContext *context,
unsigned vectorLength,
659 bool enableVLAVectorization,
bool enableSIMDIndex32)
660 : OpRewritePattern(context),
661 vl{vectorLength, enableVLAVectorization, enableSIMDIndex32} {}
663 LogicalResult matchAndRewrite(scf::ForOp op,
664 PatternRewriter &rewriter)
const override {
668 if (!op.getRegion().hasOneBlock() || !
isOneInteger(op.getStep()) ||
672 if (vectorizeStmt(rewriter, op, vl,
false) &&
673 vectorizeStmt(rewriter, op, vl,
true))
685 if (
auto forOp = redOp.getVector().getDefiningOp<scf::ForOp>()) {
687 rewriter.
replaceOp(op, redOp.getVector());
700struct ReducChainBroadcastRewriter
703 using OpRewritePattern<vector::BroadcastOp>::OpRewritePattern;
705 LogicalResult matchAndRewrite(vector::BroadcastOp op,
706 PatternRewriter &rewriter)
const override {
707 return cleanReducChain(rewriter, op, op.getSource());
716struct ReducChainInsertRewriter :
public OpRewritePattern<vector::InsertOp> {
718 using OpRewritePattern<vector::InsertOp>::OpRewritePattern;
720 LogicalResult matchAndRewrite(vector::InsertOp op,
721 PatternRewriter &rewriter)
const override {
722 return cleanReducChain(rewriter, op, op.getValueToStore());
733 unsigned vectorLength,
734 bool enableVLAVectorization,
735 bool enableSIMDIndex32) {
736 assert(vectorLength > 0);
738 patterns.
add<ForOpRewriter>(patterns.
getContext(), vectorLength,
739 enableVLAVectorization, enableSIMDIndex32);
740 patterns.
add<ReducChainInsertRewriter, ReducChainBroadcastRewriter>(
static Type getElementType(Type type)
Determine the element type of type.
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
This class represents an argument of a Block.
Block * getOwner() const
Returns the block that owns this argument.
Block represents an ordered list of Operations.
OpListType & getOperations()
Operation * getTerminator()
Get the terminator operation of this block.
reverse_iterator rbegin()
AffineExpr getAffineSymbolExpr(unsigned position)
AffineExpr getAffineDimExpr(unsigned position)
MLIRContext * getContext() const
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
void createOrFold(SmallVectorImpl< Value > &results, Location location, Args &&...args)
Create an operation of specific op type at the current insertion point, and immediately try to fold i...
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
Operation is the basic unit of execution within MLIR.
Value getOperand(unsigned idx)
Block * getBlock()
Returns the operation block that contains this operation.
unsigned getNumOperands()
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
virtual void replaceAllUsesWith(Value from, Value to)
Find uses of from and replace them with to.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static constexpr llvm::StringLiteral getLoopEmitterLoopAttrName()
A wrapper around RankedTensorType, which has three goals:
Level getLvlRank() const
Returns the level-rank.
Level getAoSCOOStart() const
Returns the starting level of this sparse tensor type for a trailing COO region that spans at least t...
Value constantIndex(OpBuilder &builder, Location loc, int64_t i)
Generates a constant of index type.
Value constantZero(OpBuilder &builder, Location loc, Type tp)
Generates a 0-valued constant of the given type.
Value constantOne(OpBuilder &builder, Location loc, Type tp)
Generates a 1-valued constant of the given type.
Value constantI1(OpBuilder &builder, Location loc, bool b)
Generates a constant of i1 type.
uint64_t Level
The type of level identifiers and level-ranks.
MemRefType getMemRefType(T &&t)
Convenience method to abbreviate casting getType().
SparseTensorType getSparseTensorType(Value val)
Convenience methods to obtain a SparseTensorType from a Value.
void populateVectorStepLoweringPatterns(RewritePatternSet &patterns, unsigned indexBitwidth=64, PatternBenefit benefit=1)
Populate the pattern set with the following patterns:
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
void populateSparseVectorizationPatterns(RewritePatternSet &patterns, unsigned vectorLength, bool enableVLAVectorization, bool enableSIMDIndex32)
Populates the given patterns list with vectorization rules.
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
bool isOneInteger(OpFoldResult v)
Return true if v is an IntegerAttr with value 1.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...