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 (auto x = dyn_cast<xxx>(def)) { \
390 vexp = xxx::create(rewriter, loc, ValueRange{vx}, x.getProperties(), \
391 x->getDiscardableAttrDictionary().getValue()); \
396#define TYPEDUNAOP(xxx) \
397 if (auto x = dyn_cast<xxx>(def)) { \
399 VectorType vtp = vectorType(vl, x.getType()); \
400 vexp = xxx::create(rewriter, loc, TypeRange{vtp}, ValueRange{vx}, \
402 x->getDiscardableAttrDictionary().getValue()); \
408 if (auto x = dyn_cast<xxx>(def)) { \
410 vexp = xxx::create(rewriter, loc, ValueRange{vx, vy}, x.getProperties(), \
411 x->getDiscardableAttrDictionary().getValue()); \
422static bool vectorizeExpr(
PatternRewriter &rewriter, scf::ForOp forOp, VL vl,
426 if (!VectorType::isValidElementType(exp.
getType()))
429 if (
auto arg = llvm::dyn_cast<BlockArgument>(exp)) {
430 if (arg == forOp.getInductionVar()) {
434 VectorType vtp = vectorType(vl, arg.
getType());
435 Value veci = vector::BroadcastOp::create(rewriter, loc, vtp, arg);
436 Value incr = vector::StepOp::create(rewriter, loc, vtp);
437 vexp = arith::AddIOp::create(rewriter, loc, veci, incr);
445 vexp = genVectorInvariantValue(rewriter, vl, exp);
453 vexp = genVectorInvariantValue(rewriter, vl, exp);
462 if (
auto load = dyn_cast<memref::LoadOp>(def)) {
463 if (hasKnownNonUnitStride(
load.getMemRef()))
465 auto subs =
load.getIndices();
467 if (vectorizeSubscripts(rewriter, forOp, vl, subs, codegen, vmask, idxs)) {
469 vexp = genVectorLoad(rewriter, loc, vl,
load.getMemRef(), idxs, vmask);
483 if (vectorizeExpr(rewriter, forOp, vl, def->
getOperand(0), codegen, vmask,
510 if (vectorizeExpr(rewriter, forOp, vl, def->
getOperand(0), codegen, vmask,
512 vectorizeExpr(rewriter, forOp, vl, def->
getOperand(1), codegen, vmask,
518 if (isa<arith::ShLIOp>(def) || isa<arith::ShRUIOp>(def) ||
519 isa<arith::ShRSIOp>(def)) {
521 if (!isInvariantValue(shiftFactor, block))
528 BINOP(arith::DivSIOp)
529 BINOP(arith::DivUIOp)
538 BINOP(arith::ShRUIOp)
539 BINOP(arith::ShRSIOp)
554static bool vectorizeStmt(
PatternRewriter &rewriter, scf::ForOp forOp, VL vl,
565 scf::YieldOp yield = cast<scf::YieldOp>(block.
getTerminator());
566 auto &last = *++block.
rbegin();
580 if (vl.enableVLAVectorization) {
582 vector::VectorScaleOp::create(rewriter, loc, rewriter.
getIndexType());
583 step = arith::MulIOp::create(rewriter, loc, vscale, step);
585 if (!yield.getResults().empty()) {
586 Value init = forOp.getInitArgs()[0];
587 VectorType vtp = vectorType(vl, init.
getType());
588 Value vinit = genVectorReducInit(rewriter, loc, yield->getOperand(0),
589 forOp.getRegionIterArg(0), init, vtp);
591 scf::ForOp::create(rewriter, loc, forOp.getLowerBound(),
592 forOp.getUpperBound(), step, vinit,
593 nullptr, forOp.getUnsignedCmp());
594 forOpNew->setDiscardableAttr(
602 vmask = genVectorMask(rewriter, loc, vl, forOp.getInductionVar(),
603 forOp.getLowerBound(), forOp.getUpperBound(), step);
608 if (!yield.getResults().empty()) {
610 if (yield->getNumOperands() != 1)
612 Value red = yield->getOperand(0);
613 Value iter = forOp.getRegionIterArg(0);
614 vector::CombiningKind kind;
616 if (isVectorizableReduction(red, iter, kind) &&
617 vectorizeExpr(rewriter, forOp, vl, red, codegen, vmask, vrhs)) {
619 Value partial = forOpNew.getResult(0);
620 Value vpass = genVectorInvariantValue(rewriter, vl, iter);
621 Value vred = arith::SelectOp::create(rewriter, loc, vmask, vrhs, vpass);
622 scf::YieldOp::create(rewriter, loc, vred);
624 Value vres = vector::ReductionOp::create(rewriter, loc, kind, partial);
630 forOpNew.getInductionVar());
632 forOpNew.getRegionIterArg(0));
637 }
else if (
auto store = dyn_cast<memref::StoreOp>(last)) {
639 if (hasKnownNonUnitStride(store.getMemRef()))
641 auto subs = store.getIndices();
643 Value rhs = store.getValue();
645 if (vectorizeSubscripts(rewriter, forOp, vl, subs, codegen, vmask, idxs) &&
646 vectorizeExpr(rewriter, forOp, vl, rhs, codegen, vmask, vrhs)) {
648 genVectorStore(rewriter, loc, store.getMemRef(), idxs, vmask, vrhs);
655 assert(!codegen &&
"cannot call codegen when analysis failed");
662 using OpRewritePattern<scf::ForOp>::OpRewritePattern;
664 ForOpRewriter(MLIRContext *context,
unsigned vectorLength,
665 bool enableVLAVectorization,
bool enableSIMDIndex32)
666 : OpRewritePattern(context),
667 vl{vectorLength, enableVLAVectorization, enableSIMDIndex32} {}
669 LogicalResult matchAndRewrite(scf::ForOp op,
670 PatternRewriter &rewriter)
const override {
674 if (!op.getRegion().hasOneBlock() || !
isOneInteger(op.getStep()) ||
678 if (vectorizeStmt(rewriter, op, vl,
false) &&
679 vectorizeStmt(rewriter, op, vl,
true))
691 if (
auto forOp = redOp.getVector().getDefiningOp<scf::ForOp>()) {
692 if (forOp->hasDiscardableAttr(
694 rewriter.
replaceOp(op, redOp.getVector());
707struct ReducChainBroadcastRewriter
710 using OpRewritePattern<vector::BroadcastOp>::OpRewritePattern;
712 LogicalResult matchAndRewrite(vector::BroadcastOp op,
713 PatternRewriter &rewriter)
const override {
714 return cleanReducChain(rewriter, op, op.getSource());
723struct ReducChainInsertRewriter :
public OpRewritePattern<vector::InsertOp> {
725 using OpRewritePattern<vector::InsertOp>::OpRewritePattern;
727 LogicalResult matchAndRewrite(vector::InsertOp op,
728 PatternRewriter &rewriter)
const override {
729 return cleanReducChain(rewriter, op, op.getValueToStore());
740 unsigned vectorLength,
741 bool enableVLAVectorization,
742 bool enableSIMDIndex32) {
743 assert(vectorLength > 0);
745 patterns.
add<ForOpRewriter>(patterns.
getContext(), vectorLength,
746 enableVLAVectorization, enableSIMDIndex32);
747 patterns.
add<ReducChainInsertRewriter, ReducChainBroadcastRewriter>(
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
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...