30 #include "llvm/ADT/ArrayRef.h"
31 #include "llvm/ADT/STLExtras.h"
32 #include "llvm/ADT/SmallVector.h"
33 #include "llvm/ADT/SmallVectorExtras.h"
34 #include "llvm/Support/FormatVariadic.h"
45 return (*attr.getAsValueRange<IntegerAttr>().begin()).getZExtValue();
53 if (
auto vectorType = dyn_cast<VectorType>(type))
54 return vectorType.getNumElements() * vectorType.getElementTypeBitWidth();
64 matchAndRewrite(vector::ShapeCastOp shapeCastOp, OpAdaptor adaptor,
66 Type dstType = getTypeConverter()->convertType(shapeCastOp.getType());
72 if (dstType == adaptor.getSource().getType() ||
73 shapeCastOp.getResultVectorType().getNumElements() == 1) {
74 rewriter.
replaceOp(shapeCastOp, adaptor.getSource());
83 struct VectorBitcastConvert final
88 matchAndRewrite(vector::BitCastOp bitcastOp, OpAdaptor adaptor,
90 Type dstType = getTypeConverter()->convertType(bitcastOp.getType());
94 if (dstType == adaptor.getSource().getType()) {
95 rewriter.
replaceOp(bitcastOp, adaptor.getSource());
102 Type srcType = adaptor.getSource().getType();
106 llvm::formatv(
"different source ({0}) and target ({1}) bitwidth",
111 adaptor.getSource());
116 struct VectorBroadcastConvert final
121 matchAndRewrite(vector::BroadcastOp castOp, OpAdaptor adaptor,
124 getTypeConverter()->convertType(castOp.getResultVectorType());
128 if (isa<spirv::ScalarType>(resultType)) {
129 rewriter.
replaceOp(castOp, adaptor.getSource());
134 adaptor.getSource());
141 struct VectorExtractOpConvert final
146 matchAndRewrite(vector::ExtractOp extractOp, OpAdaptor adaptor,
148 Type dstType = getTypeConverter()->convertType(extractOp.getType());
152 if (isa<spirv::ScalarType>(adaptor.getVector().getType())) {
153 rewriter.
replaceOp(extractOp, adaptor.getVector());
157 if (std::optional<int64_t>
id =
160 extractOp, dstType, adaptor.getVector(),
164 extractOp, dstType, adaptor.getVector(),
165 adaptor.getDynamicPosition()[0]);
170 struct VectorExtractStridedSliceOpConvert final
175 matchAndRewrite(vector::ExtractStridedSliceOp extractOp, OpAdaptor adaptor,
177 Type dstType = getTypeConverter()->convertType(extractOp.getType());
187 Value srcVector = adaptor.getOperands().front();
190 if (isa<spirv::ScalarType>(dstType)) {
197 std::iota(indices.begin(), indices.end(), offset);
200 extractOp, dstType, srcVector, srcVector,
207 template <
class SPIRVFMAOp>
212 matchAndRewrite(vector::FMAOp fmaOp, OpAdaptor adaptor,
214 Type dstType = getTypeConverter()->convertType(fmaOp.getType());
218 adaptor.getRhs(), adaptor.getAcc());
223 struct VectorFromElementsOpConvert final
228 matchAndRewrite(vector::FromElementsOp op, OpAdaptor adaptor,
230 Type resultType = getTypeConverter()->convertType(op.getType());
234 if (isa<spirv::ScalarType>(resultType)) {
242 assert(cast<VectorType>(resultType).getRank() == 1);
249 struct VectorInsertOpConvert final
254 matchAndRewrite(vector::InsertOp insertOp, OpAdaptor adaptor,
256 if (isa<VectorType>(insertOp.getSourceType()))
258 if (!getTypeConverter()->convertType(insertOp.getDestVectorType()))
260 "unsupported dest vector type");
263 if (insertOp.getSourceType().isIntOrFloat() &&
264 insertOp.getDestVectorType().getNumElements() == 1) {
265 rewriter.
replaceOp(insertOp, adaptor.getSource());
269 if (std::optional<int64_t>
id =
272 insertOp, adaptor.getSource(), adaptor.getDest(),
id.value());
275 insertOp, insertOp.getDest(), adaptor.getSource(),
276 adaptor.getDynamicPosition()[0]);
281 struct VectorExtractElementOpConvert final
286 matchAndRewrite(vector::ExtractElementOp extractOp, OpAdaptor adaptor,
288 Type resultType = getTypeConverter()->convertType(extractOp.getType());
292 if (isa<spirv::ScalarType>(adaptor.getVector().getType())) {
293 rewriter.
replaceOp(extractOp, adaptor.getVector());
300 extractOp, resultType, adaptor.getVector(),
304 extractOp, resultType, adaptor.getVector(), adaptor.getPosition());
309 struct VectorInsertElementOpConvert final
314 matchAndRewrite(vector::InsertElementOp insertOp, OpAdaptor adaptor,
316 Type vectorType = getTypeConverter()->convertType(insertOp.getType());
320 if (isa<spirv::ScalarType>(vectorType)) {
321 rewriter.
replaceOp(insertOp, adaptor.getSource());
328 insertOp, adaptor.getSource(), adaptor.getDest(),
329 cstPos.getSExtValue());
332 insertOp, vectorType, insertOp.getDest(), adaptor.getSource(),
333 adaptor.getPosition());
338 struct VectorInsertStridedSliceOpConvert final
343 matchAndRewrite(vector::InsertStridedSliceOp insertOp, OpAdaptor adaptor,
345 Value srcVector = adaptor.getOperands().front();
346 Value dstVector = adaptor.getOperands().back();
353 if (isa<spirv::ScalarType>(srcVector.
getType())) {
354 assert(!isa<spirv::ScalarType>(dstVector.
getType()));
356 insertOp, dstVector.
getType(), srcVector, dstVector,
361 uint64_t totalSize = cast<VectorType>(dstVector.getType()).getNumElements();
362 uint64_t insertSize =
363 cast<VectorType>(srcVector.
getType()).getNumElements();
366 std::iota(indices.begin(), indices.end(), 0);
367 std::iota(indices.begin() + offset, indices.begin() + offset + insertSize,
371 insertOp, dstVector.getType(), dstVector, srcVector,
379 vector::ReductionOp reduceOp, vector::ReductionOp::Adaptor adaptor,
381 int numElements =
static_cast<int>(srcVectorType.getDimSize(0));
383 values.reserve(numElements + (adaptor.getAcc() ? 1 : 0));
386 for (
int i = 0; i < numElements; ++i) {
387 values.push_back(rewriter.
create<spirv::CompositeExtractOp>(
388 loc, srcVectorType.getElementType(), adaptor.getVector(),
391 if (
Value acc = adaptor.getAcc())
392 values.push_back(acc);
397 struct ReductionRewriteInfo {
402 FailureOr<ReductionRewriteInfo>
static getReductionInfo(
403 vector::ReductionOp op, vector::ReductionOp::Adaptor adaptor,
409 auto srcVectorType = dyn_cast<VectorType>(adaptor.getVector().getType());
410 if (!srcVectorType || srcVectorType.getRank() != 1)
414 extractAllElements(op, adaptor, srcVectorType, rewriter);
416 return ReductionRewriteInfo{resultType, std::move(extractedElements)};
419 template <
typename SPIRVUMaxOp,
typename SPIRVUMinOp,
typename SPIRVSMaxOp,
420 typename SPIRVSMinOp>
425 matchAndRewrite(vector::ReductionOp reduceOp, OpAdaptor adaptor,
428 getReductionInfo(reduceOp, adaptor, rewriter, *getTypeConverter());
429 if (failed(reductionInfo))
432 auto [resultType, extractedElements] = *reductionInfo;
434 Value result = extractedElements.front();
435 for (
Value next : llvm::drop_begin(extractedElements)) {
436 switch (reduceOp.getKind()) {
438 #define INT_AND_FLOAT_CASE(kind, iop, fop) \
439 case vector::CombiningKind::kind: \
440 if (llvm::isa<IntegerType>(resultType)) { \
441 result = rewriter.create<spirv::iop>(loc, resultType, result, next); \
443 assert(llvm::isa<FloatType>(resultType)); \
444 result = rewriter.create<spirv::fop>(loc, resultType, result, next); \
448 #define INT_OR_FLOAT_CASE(kind, fop) \
449 case vector::CombiningKind::kind: \
450 result = rewriter.create<fop>(loc, resultType, result, next); \
460 case vector::CombiningKind::AND:
461 case vector::CombiningKind::OR:
462 case vector::CombiningKind::XOR:
467 #undef INT_AND_FLOAT_CASE
468 #undef INT_OR_FLOAT_CASE
476 template <
typename SPIRVFMaxOp,
typename SPIRVFMinOp>
477 struct VectorReductionFloatMinMax final
482 matchAndRewrite(vector::ReductionOp reduceOp, OpAdaptor adaptor,
485 getReductionInfo(reduceOp, adaptor, rewriter, *getTypeConverter());
486 if (failed(reductionInfo))
489 auto [resultType, extractedElements] = *reductionInfo;
491 Value result = extractedElements.front();
492 for (
Value next : llvm::drop_begin(extractedElements)) {
493 switch (reduceOp.getKind()) {
495 #define INT_OR_FLOAT_CASE(kind, fop) \
496 case vector::CombiningKind::kind: \
497 result = rewriter.create<fop>(loc, resultType, result, next); \
508 #undef INT_OR_FLOAT_CASE
521 matchAndRewrite(vector::SplatOp op, OpAdaptor adaptor,
523 Type dstType = getTypeConverter()->convertType(op.getType());
526 if (isa<spirv::ScalarType>(dstType)) {
527 rewriter.
replaceOp(op, adaptor.getInput());
529 auto dstVecType = cast<VectorType>(dstType);
539 struct VectorShuffleOpConvert final
544 matchAndRewrite(vector::ShuffleOp shuffleOp, OpAdaptor adaptor,
546 VectorType oldResultType = shuffleOp.getResultVectorType();
547 Type newResultType = getTypeConverter()->convertType(oldResultType);
550 "unsupported result vector type");
552 auto mask = llvm::to_vector_of<int32_t>(shuffleOp.getMask());
554 VectorType oldV1Type = shuffleOp.getV1VectorType();
555 VectorType oldV2Type = shuffleOp.getV2VectorType();
559 if (oldV1Type.getNumElements() > 1 && oldV2Type.getNumElements() > 1 &&
560 oldResultType.getNumElements() > 1) {
562 shuffleOp, newResultType, adaptor.getV1(), adaptor.getV2(),
570 auto getElementAtIdx = [&rewriter, loc = shuffleOp.getLoc()](
572 if (
auto vecTy = dyn_cast<VectorType>(scalarOrVec.getType()))
573 return rewriter.
create<spirv::CompositeExtractOp>(loc, scalarOrVec,
576 assert(idx == 0 &&
"Invalid scalar element index");
580 int32_t numV1Elems = oldV1Type.getNumElements();
582 for (
auto [shuffleIdx, newOperand] : llvm::zip_equal(mask, newOperands)) {
583 Value vec = adaptor.getV1();
584 int32_t elementIdx = shuffleIdx;
585 if (elementIdx >= numV1Elems) {
586 vec = adaptor.getV2();
587 elementIdx -= numV1Elems;
590 newOperand = getElementAtIdx(vec, elementIdx);
594 if (newOperands.size() == 1) {
595 rewriter.
replaceOp(shuffleOp, newOperands.front());
600 shuffleOp, newResultType, newOperands);
605 struct VectorInterleaveOpConvert final
610 matchAndRewrite(vector::InterleaveOp interleaveOp, OpAdaptor adaptor,
613 VectorType oldResultType = interleaveOp.getResultVectorType();
614 Type newResultType = getTypeConverter()->convertType(oldResultType);
617 "unsupported result vector type");
620 VectorType sourceType = interleaveOp.getSourceVectorType();
621 int n = sourceType.getNumElements();
627 Value newOperands[] = {adaptor.getLhs(), adaptor.getRhs()};
629 interleaveOp, newResultType, newOperands);
633 auto seq = llvm::seq<int64_t>(2 * n);
634 auto indices = llvm::map_to_vector(
635 seq, [n](
int i) {
return (i % 2 ? n : 0) + i / 2; });
639 interleaveOp, newResultType, adaptor.getLhs(), adaptor.getRhs(),
646 struct VectorDeinterleaveOpConvert final
651 matchAndRewrite(vector::DeinterleaveOp deinterleaveOp, OpAdaptor adaptor,
655 VectorType oldResultType = deinterleaveOp.getResultVectorType();
656 Type newResultType = getTypeConverter()->convertType(oldResultType);
659 "unsupported result vector type");
661 Location loc = deinterleaveOp->getLoc();
664 Value sourceVector = adaptor.getSource();
665 VectorType sourceType = deinterleaveOp.getSourceVectorType();
666 int n = sourceType.getNumElements();
672 auto elem0 = rewriter.
create<spirv::CompositeExtractOp>(
675 auto elem1 = rewriter.
create<spirv::CompositeExtractOp>(
678 rewriter.
replaceOp(deinterleaveOp, {elem0, elem1});
683 auto seqEven = llvm::seq<int64_t>(n / 2);
685 llvm::map_to_vector(seqEven, [](
int i) {
return i * 2; });
688 auto seqOdd = llvm::seq<int64_t>(n / 2);
690 llvm::map_to_vector(seqOdd, [](
int i) {
return i * 2 + 1; });
693 auto shuffleEven = rewriter.
create<spirv::VectorShuffleOp>(
694 loc, newResultType, sourceVector, sourceVector,
697 auto shuffleOdd = rewriter.
create<spirv::VectorShuffleOp>(
698 loc, newResultType, sourceVector, sourceVector,
701 rewriter.
replaceOp(deinterleaveOp, {shuffleEven, shuffleOdd});
706 struct VectorLoadOpConverter final
711 matchAndRewrite(vector::LoadOp loadOp, OpAdaptor adaptor,
713 auto memrefType = loadOp.getMemRefType();
715 dyn_cast_or_null<spirv::StorageClassAttr>(memrefType.getMemorySpace());
718 loadOp,
"expected spirv.storage_class memory space");
720 const auto &typeConverter = *getTypeConverter<SPIRVTypeConverter>();
721 auto loc = loadOp.getLoc();
724 adaptor.getIndices(), loc, rewriter);
727 loadOp,
"failed to get memref element pointer");
729 spirv::StorageClass storageClass = attr.getValue();
730 auto vectorType = loadOp.getVectorType();
732 Value castedAccessChain =
733 rewriter.
create<spirv::BitcastOp>(loc, vectorPtrType, accessChain);
741 struct VectorStoreOpConverter final
746 matchAndRewrite(vector::StoreOp storeOp, OpAdaptor adaptor,
748 auto memrefType = storeOp.getMemRefType();
750 dyn_cast_or_null<spirv::StorageClassAttr>(memrefType.getMemorySpace());
753 storeOp,
"expected spirv.storage_class memory space");
755 const auto &typeConverter = *getTypeConverter<SPIRVTypeConverter>();
756 auto loc = storeOp.getLoc();
759 adaptor.getIndices(), loc, rewriter);
762 storeOp,
"failed to get memref element pointer");
764 spirv::StorageClass storageClass = attr.getValue();
765 auto vectorType = storeOp.getVectorType();
767 Value castedAccessChain =
768 rewriter.
create<spirv::BitcastOp>(loc, vectorPtrType, accessChain);
770 adaptor.getValueToStore());
776 struct VectorReductionToIntDotProd final
780 LogicalResult matchAndRewrite(vector::ReductionOp op,
782 if (op.getKind() != vector::CombiningKind::ADD)
785 auto resultType = dyn_cast<IntegerType>(op.getType());
790 if (!llvm::is_contained({32, 64}, resultBitwidth))
793 VectorType inVecTy = op.getSourceVectorType();
794 if (!llvm::is_contained({4, 3}, inVecTy.getNumElements()) ||
795 inVecTy.getShape().size() != 1 || inVecTy.isScalable())
798 auto mul = op.getVector().getDefiningOp<arith::MulIOp>();
801 op,
"reduction operand is not 'arith.muli'");
803 if (succeeded(handleCase<arith::ExtSIOp, arith::ExtSIOp, spirv::SDotOp,
804 spirv::SDotAccSatOp,
false>(op, mul, rewriter)))
807 if (succeeded(handleCase<arith::ExtUIOp, arith::ExtUIOp, spirv::UDotOp,
808 spirv::UDotAccSatOp,
false>(op, mul, rewriter)))
811 if (succeeded(handleCase<arith::ExtSIOp, arith::ExtUIOp, spirv::SUDotOp,
812 spirv::SUDotAccSatOp,
false>(op, mul, rewriter)))
815 if (succeeded(handleCase<arith::ExtUIOp, arith::ExtSIOp, spirv::SUDotOp,
816 spirv::SUDotAccSatOp,
true>(op, mul, rewriter)))
823 template <
typename LhsExtensionOp,
typename RhsExtensionOp,
typename DotOp,
824 typename DotAccOp,
bool SwapOperands>
825 static LogicalResult handleCase(vector::ReductionOp op, arith::MulIOp mul,
827 auto lhs = mul.getLhs().getDefiningOp<LhsExtensionOp>();
830 Value lhsIn = lhs.getIn();
831 auto lhsInType = cast<VectorType>(lhsIn.
getType());
832 if (!lhsInType.getElementType().isInteger(8))
835 auto rhs = mul.getRhs().getDefiningOp<RhsExtensionOp>();
838 Value rhsIn = rhs.getIn();
839 auto rhsInType = cast<VectorType>(rhsIn.
getType());
840 if (!rhsInType.getElementType().isInteger(8))
843 if (op.getSourceVectorType().getNumElements() == 3) {
844 IntegerType i8Type = rewriter.
getI8Type();
848 lhsIn = rewriter.
create<spirv::CompositeConstructOp>(
850 rhsIn = rewriter.
create<spirv::CompositeConstructOp>(
857 std::swap(lhsIn, rhsIn);
859 if (
Value acc = op.getAcc()) {
871 struct VectorReductionToFPDotProd final
876 matchAndRewrite(vector::ReductionOp op, OpAdaptor adaptor,
878 if (op.getKind() != vector::CombiningKind::ADD)
881 auto resultType = getTypeConverter()->convertType<
FloatType>(op.getType());
885 Value vec = adaptor.getVector();
886 Value acc = adaptor.getAcc();
888 auto vectorType = dyn_cast<VectorType>(vec.
getType());
890 assert(isa<FloatType>(vec.
getType()) &&
891 "Expected the vector to be scalarized");
912 rewriter.
getFloatAttr(vectorType.getElementType(), 1.0);
914 rhs = rewriter.
create<spirv::ConstantOp>(loc, vectorType, oneAttr);
919 Value res = rewriter.
create<spirv::DotOp>(loc, resultType, lhs, rhs);
921 res = rewriter.
create<spirv::FAddOp>(loc, acc, res);
932 matchAndRewrite(vector::StepOp stepOp, OpAdaptor adaptor,
934 const auto &typeConverter = *getTypeConverter<SPIRVTypeConverter>();
940 int64_t numElements = stepOp.getType().getNumElements();
946 if (numElements == 1) {
953 source.reserve(numElements);
954 for (int64_t i = 0; i < numElements; ++i) {
956 Value constOp = rewriter.
create<spirv::ConstantOp>(loc, intType, intAttr);
957 source.push_back(constOp);
966 #define CL_INT_MAX_MIN_OPS \
967 spirv::CLUMaxOp, spirv::CLUMinOp, spirv::CLSMaxOp, spirv::CLSMinOp
969 #define GL_INT_MAX_MIN_OPS \
970 spirv::GLUMaxOp, spirv::GLUMinOp, spirv::GLSMaxOp, spirv::GLSMinOp
972 #define CL_FLOAT_MAX_MIN_OPS spirv::CLFMaxOp, spirv::CLFMinOp
973 #define GL_FLOAT_MAX_MIN_OPS spirv::GLFMaxOp, spirv::GLFMinOp
978 VectorBitcastConvert, VectorBroadcastConvert,
979 VectorExtractElementOpConvert, VectorExtractOpConvert,
980 VectorExtractStridedSliceOpConvert, VectorFmaOpConvert<spirv::GLFmaOp>,
981 VectorFmaOpConvert<spirv::CLFmaOp>, VectorFromElementsOpConvert,
982 VectorInsertElementOpConvert, VectorInsertOpConvert,
983 VectorReductionPattern<GL_INT_MAX_MIN_OPS>,
984 VectorReductionPattern<CL_INT_MAX_MIN_OPS>,
985 VectorReductionFloatMinMax<CL_FLOAT_MAX_MIN_OPS>,
986 VectorReductionFloatMinMax<GL_FLOAT_MAX_MIN_OPS>, VectorShapeCast,
987 VectorInsertStridedSliceOpConvert, VectorShuffleOpConvert,
988 VectorInterleaveOpConvert, VectorDeinterleaveOpConvert,
989 VectorSplatPattern, VectorLoadOpConverter, VectorStoreOpConverter,
990 VectorStepOpConvert>(typeConverter,
patterns.getContext(),
995 patterns.add<VectorReductionToFPDotProd>(typeConverter,
patterns.getContext(),
static Value getZero(OpBuilder &b, Location loc, Type elementType)
Get zero value for an element type.
static uint64_t getFirstIntValue(ArrayAttr attr)
Returns the integer value from the first valid input element, assuming Value inputs are defined by a ...
static int getNumBits(Type type)
Returns the number of bits for the given scalar/vector type.
#define INT_AND_FLOAT_CASE(kind, iop, fop)
#define INT_OR_FLOAT_CASE(kind, fop)
Attributes are known-constant values of operations.
IntegerAttr getIntegerAttr(Type type, int64_t value)
ArrayAttr getI32ArrayAttr(ArrayRef< int32_t > values)
FloatAttr getFloatAttr(Type type, double value)
IntegerType getIntegerType(unsigned width)
This class implements a pattern rewriter for use with ConversionPatterns.
void replaceOp(Operation *op, ValueRange newValues) override
Replace the given operation with the new values.
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
OpConversionPattern is a wrapper around ConversionPattern that allows for matching and rewriting agai...
OpConversionPattern(MLIRContext *context, PatternBenefit benefit=1)
This class implements the operand iterators for the Operation class.
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
Type conversion from builtin types to SPIR-V types for shader interface.
LogicalResult convertType(Type t, SmallVectorImpl< Type > &results) const
Convert the given type.
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.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static PointerType get(Type pointeeType, StorageClass storageClass)
Value getElementPtr(const SPIRVTypeConverter &typeConverter, MemRefType baseType, Value basePtr, ValueRange indices, Location loc, OpBuilder &builder)
Performs the index computation to get to the element at indices of the memory pointed to by basePtr,...
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
detail::constant_int_value_binder m_ConstantInt(IntegerAttr::ValueType *bind_value)
Matches a constant holding a scalar/vector/tensor integer (splat) and writes the integer value to bin...
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
void populateVectorReductionToSPIRVDotProductPatterns(RewritePatternSet &patterns)
Appends patterns to convert vector reduction of the form:
const FrozenRewritePatternSet & patterns
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
void populateVectorToSPIRVPatterns(const SPIRVTypeConverter &typeConverter, RewritePatternSet &patterns)
Appends to a pattern list additional patterns for translating Vector Ops to SPIR-V ops.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
OpRewritePattern(MLIRContext *context, PatternBenefit benefit=1, ArrayRef< StringRef > generatedNames={})
Patterns must specify the root operation name they match against, and can also specify the benefit of...