34#include "llvm/ADT/SmallVector.h"
35#include "llvm/Support/DebugLog.h"
36#include "llvm/Support/MathExtras.h"
37#include "llvm/Support/raw_ostream.h"
45#define DEBUG_TYPE "vector-narrow-type-emulation"
81 int numSrcElemsPerDest,
82 int numFrontPadElems = 0) {
84 assert(numFrontPadElems < numSrcElemsPerDest &&
85 "numFrontPadElems must be less than numSrcElemsPerDest");
88 (numFrontPadElems + numSrcElems + numSrcElemsPerDest - 1) /
99 !isa<arith::ConstantOp, vector::CreateMaskOp, vector::ConstantMaskOp>(
101 auto extractOp = dyn_cast<vector::ExtractOp>(maskOp);
104 maskOp = extractOp.getSource().getDefiningOp();
105 extractOps.push_back(extractOp);
110 if (!isa_and_present<arith::ConstantOp, vector::CreateMaskOp,
111 vector::ConstantMaskOp>(maskOp))
118 maskShape.back() = numDestElems;
119 auto newMaskType = VectorType::get(maskShape, rewriter.
getI1Type());
120 std::optional<Operation *> newMask =
123 [&](vector::CreateMaskOp createMaskOp)
124 -> std::optional<Operation *> {
134 s0 = (s0 + numFrontPadElems).ceilDiv(numSrcElemsPerDest);
137 rewriter, loc, s0, origIndex);
139 newMaskOperands.push_back(
141 return vector::CreateMaskOp::create(rewriter, loc, newMaskType,
144 .Case([&](vector::ConstantMaskOp constantMaskOp)
145 -> std::optional<Operation *> {
148 int64_t &maskIndex = maskDimSizes.back();
149 maskIndex = llvm::divideCeil(numFrontPadElems + maskIndex,
151 return vector::ConstantMaskOp::create(rewriter, loc, newMaskType,
154 .Case([&](arith::ConstantOp constantOp)
155 -> std::optional<Operation *> {
157 if (maskShape.size() != 1)
174 cast<DenseIntElementsAttr>(constantOp.getValue());
176 paddedMaskValues.append(originalMask.template value_begin<bool>(),
177 originalMask.template value_end<bool>());
178 paddedMaskValues.resize(numDestElems * numSrcElemsPerDest,
false);
182 for (
size_t i = 0; i < paddedMaskValues.size();
183 i += numSrcElemsPerDest) {
184 bool combinedValue =
false;
185 for (
int j = 0;
j < numSrcElemsPerDest; ++
j) {
186 combinedValue |= paddedMaskValues[i +
j];
188 compressedMaskValues.push_back(combinedValue);
190 return arith::ConstantOp::create(
198 while (!extractOps.empty()) {
200 vector::ExtractOp::create(rewriter, loc, (*newMask)->getResults()[0],
201 extractOps.back().getMixedPosition());
202 extractOps.pop_back();
224 auto vectorType = cast<VectorType>(src.
getType());
225 assert(vectorType.getRank() == 1 &&
"expected source to be rank-1-D vector ");
226 assert(offset + numElemsToExtract <= vectorType.getNumElements() &&
227 "subvector out of bounds");
231 if (vectorType.getNumElements() == numElemsToExtract)
238 auto resultVectorType =
239 VectorType::get({numElemsToExtract}, vectorType.getElementType());
240 return vector::ExtractStridedSliceOp::create(rewriter, loc, resultVectorType,
241 src, offsets, sizes, strides)
256 [[maybe_unused]]
auto srcVecTy = cast<VectorType>(src.
getType());
257 [[maybe_unused]]
auto destVecTy = cast<VectorType>(dest.
getType());
258 assert(srcVecTy.getRank() == 1 && destVecTy.getRank() == 1 &&
259 "expected source and dest to be rank-1 vector types");
262 if (srcVecTy.getNumElements() == destVecTy.getNumElements() && offset == 0)
267 return vector::InsertStridedSliceOp::create(rewriter, loc, destVecTy, src,
268 dest, offsets, strides);
294 auto srcVecTy = cast<VectorType>(src.
getType());
295 assert(srcVecTy.getRank() == 1 &&
"expected source to be rank-1-D vector ");
299 assert(numElemsToExtract <= srcVecTy.getNumElements() &&
300 "subvector out of bounds");
304 if (srcVecTy.getNumElements() == numElemsToExtract)
307 for (
int i = 0; i < numElemsToExtract; ++i) {
309 (i == 0) ? dyn_cast<Value>(offset)
310 : arith::AddIOp::create(
312 dyn_cast<Value>(offset),
314 auto extractOp = vector::ExtractOp::create(rewriter, loc, src, extractLoc);
315 dest = vector::InsertOp::create(rewriter, loc, extractOp, dest, i);
338 auto srcVecTy = cast<VectorType>(src.
getType());
339 auto destVecTy = cast<VectorType>(dest.
getType());
340 assert(srcVecTy.getRank() == 1 && destVecTy.getRank() == 1 &&
341 "expected source and dest to be rank-1 vector types");
344 assert(numElemsToInsert > 0 &&
345 "the number of elements to insert must be greater than 0");
349 assert(numElemsToInsert <= destVecTy.getNumElements() &&
350 "subvector out of bounds");
353 for (
int64_t i = 0; i < numElemsToInsert; ++i) {
355 i == 0 ? destOffsetVal
356 : arith::AddIOp::create(
359 auto extractOp = vector::ExtractOp::create(rewriter, loc, src, i);
360 dest = vector::InsertOp::create(rewriter, loc, extractOp, dest, insertLoc);
374 int64_t numContainerElemsToLoad,
376 Type containerElemTy) {
379 auto newLoad = vector::LoadOp::create(
380 rewriter, loc, VectorType::get(numContainerElemsToLoad, containerElemTy),
382 return vector::BitCastOp::create(
384 VectorType::get(numContainerElemsToLoad * emulatedPerContainerElem,
392 VectorType downcastType,
393 VectorType upcastType,
Value mask,
396 downcastType.getNumElements() * downcastType.getElementTypeBitWidth() ==
397 upcastType.getNumElements() * upcastType.getElementTypeBitWidth() &&
398 "expected input and output number of bits to match");
399 if (trueValue.
getType() != downcastType) {
401 vector::BitCastOp::create(builder, loc, downcastType, trueValue);
403 if (falseValue.
getType() != downcastType) {
405 vector::BitCastOp::create(builder, loc, downcastType, falseValue);
408 arith::SelectOp::create(builder, loc, mask, trueValue, falseValue);
410 return vector::BitCastOp::create(builder, loc, upcastType, selectedType);
429 assert(valueToStore.getType().getRank() == 1 &&
"expected 1-D vector");
433 auto atomicOp = memref::GenericAtomicRMWOp::create(
434 builder, loc, linearizedMemref,
ValueRange{storeIdx});
435 Value origValue = atomicOp.getCurrentValue();
442 auto oneElemVecType = VectorType::get({1}, origValue.getType());
443 Value origVecValue = vector::FromElementsOp::create(
444 builder, loc, oneElemVecType,
ValueRange{origValue});
449 oneElemVecType, mask, valueToStore, origVecValue);
450 auto scalarMaskedValue =
451 vector::ExtractOp::create(builder, loc, maskedValue, 0);
452 memref::AtomicYieldOp::create(builder, loc, scalarMaskedValue);
460 assert(valueToStore.getType().getRank() == 1 &&
"expected 1-D vector");
462 auto oneElemVecType =
463 VectorType::get({1}, linearizedMemref.getType().
getElementType());
465 vector::LoadOp::create(builder, loc, oneElemVecType, linearizedMemref,
467 origVecValue = vector::BitCastOp::create(builder, loc, valueToStore.getType(),
472 oneElemVecType, mask, valueToStore, origVecValue);
473 vector::StoreOp::create(builder, loc, maskedValue, linearizedMemref,
491 assert(
vector.getType().getRank() == 1 &&
"expected 1-D vector");
492 auto vectorElementType =
vector.getType().getElementType();
496 sliceNumElements * vectorElementType.getIntOrFloatBitWidth() <= 8 &&
497 "sliceNumElements * vector element size must be less than or equal to 8");
498 assert(8 % vectorElementType.getIntOrFloatBitWidth() == 0 &&
499 "vector element must be a valid sub-byte type");
500 auto emulatedPerContainerElem = 8 / vectorElementType.getIntOrFloatBitWidth();
501 auto emptyByteVector = arith::ConstantOp::create(
503 VectorType::get({emulatedPerContainerElem}, vectorElementType),
504 rewriter.getZeroAttr(
505 VectorType::get({emulatedPerContainerElem}, vectorElementType)));
507 extractOffset, sliceNumElements);
564struct ConvertVectorStore final : OpConversionPattern<vector::StoreOp> {
567 ConvertVectorStore(MLIRContext *context,
bool disableAtomicRMW,
569 : OpConversionPattern<vector::StoreOp>(context),
570 disableAtomicRMW(disableAtomicRMW), assumeAligned(assumeAligned) {}
573 matchAndRewrite(vector::StoreOp op, OpAdaptor adaptor,
574 ConversionPatternRewriter &rewriter)
const override {
576 if (op.getValueToStore().getType().getRank() != 1)
577 return rewriter.notifyMatchFailure(op,
578 "only 1-D vectors are supported ATM");
580 auto loc = op.getLoc();
582 auto valueToStore = cast<VectorValue>(op.getValueToStore());
583 auto containerElemTy =
584 cast<MemRefType>(adaptor.getBase().getType()).getElementType();
585 Type emulatedElemTy = op.getValueToStore().getType().getElementType();
587 int containerBits = containerElemTy.getIntOrFloatBitWidth();
590 if (containerBits % emulatedBits != 0) {
591 return rewriter.notifyMatchFailure(
592 op,
"impossible to pack emulated elements into container elements "
593 "(bit-wise misalignment)");
595 int emulatedPerContainerElem = containerBits / emulatedBits;
610 auto origElements = valueToStore.getType().getNumElements();
612 bool isDivisibleInSize = origElements % emulatedPerContainerElem == 0;
618 if (!isDivisibleInSize)
619 return rewriter.notifyMatchFailure(
620 op,
"the source vector does not fill whole container elements "
621 "(not divisible in size)");
623 auto stridedMetadata =
624 memref::ExtractStridedMetadataOp::create(rewriter, loc, op.getBase());
625 OpFoldResult linearizedIndices;
626 std::tie(std::ignore, linearizedIndices) =
628 rewriter, loc, emulatedBits, containerBits,
629 stridedMetadata.getConstifiedMixedOffset(),
630 stridedMetadata.getConstifiedMixedSizes(),
631 stridedMetadata.getConstifiedMixedStrides(),
633 auto memrefBase = cast<MemRefValue>(adaptor.getBase());
634 int numElements = origElements / emulatedPerContainerElem;
635 auto bitCast = vector::BitCastOp::create(
636 rewriter, loc, VectorType::get(numElements, containerElemTy),
637 op.getValueToStore());
638 rewriter.replaceOpWithNewOp<vector::StoreOp>(
639 op, bitCast.getResult(), memrefBase,
644 auto stridedMetadata =
645 memref::ExtractStridedMetadataOp::create(rewriter, loc, op.getBase());
647 OpFoldResult linearizedIndices;
648 memref::LinearizedMemRefInfo linearizedInfo;
649 std::tie(linearizedInfo, linearizedIndices) =
651 rewriter, loc, emulatedBits, containerBits,
652 stridedMetadata.getConstifiedMixedOffset(),
653 stridedMetadata.getConstifiedMixedSizes(),
654 stridedMetadata.getConstifiedMixedStrides(),
661 std::optional<int64_t> foldedNumFrontPadElems =
664 if (!foldedNumFrontPadElems) {
665 return rewriter.notifyMatchFailure(
666 op,
"subbyte store emulation: dynamic front padding size is "
667 "not yet implemented");
670 auto memrefBase = cast<MemRefValue>(adaptor.getBase());
702 bool emulationRequiresPartialStores = *foldedNumFrontPadElems != 0;
704 if (!emulationRequiresPartialStores) {
706 auto numElements = origElements / emulatedPerContainerElem;
707 auto bitCast = vector::BitCastOp::create(
708 rewriter, loc, VectorType::get(numElements, containerElemTy),
709 op.getValueToStore());
710 rewriter.replaceOpWithNewOp<vector::StoreOp>(
711 op, bitCast.getResult(), memrefBase,
747 Value currentDestIndex =
750 auto currentSourceIndex = 0;
753 auto subWidthStoreMaskType =
754 VectorType::get({emulatedPerContainerElem}, rewriter.getI1Type());
762 auto frontSubWidthStoreElem =
763 (emulatedPerContainerElem - *foldedNumFrontPadElems) %
764 emulatedPerContainerElem;
765 if (frontSubWidthStoreElem > 0) {
766 SmallVector<bool> frontMaskValues(emulatedPerContainerElem,
false);
767 if (*foldedNumFrontPadElems + origElements < emulatedPerContainerElem) {
768 std::fill_n(frontMaskValues.begin() + *foldedNumFrontPadElems,
770 frontSubWidthStoreElem = origElements;
772 std::fill_n(frontMaskValues.end() - frontSubWidthStoreElem,
773 *foldedNumFrontPadElems,
true);
775 auto frontMask = arith::ConstantOp::create(
779 currentSourceIndex = emulatedPerContainerElem - (*foldedNumFrontPadElems);
782 frontSubWidthStoreElem, *foldedNumFrontPadElems);
784 storeFunc(rewriter, loc, memrefBase, currentDestIndex,
785 cast<VectorValue>(value), frontMask.getResult());
788 if (currentSourceIndex >= origElements) {
789 rewriter.eraseOp(op);
796 currentDestIndex = arith::AddIOp::create(
797 rewriter, loc, rewriter.getIndexType(), currentDestIndex, constantOne);
802 int64_t fullWidthStoreSize =
803 (origElements - currentSourceIndex) / emulatedPerContainerElem;
804 int64_t numNonFullWidthElements =
805 fullWidthStoreSize * emulatedPerContainerElem;
806 if (fullWidthStoreSize > 0) {
808 rewriter, loc, valueToStore, currentSourceIndex,
809 numNonFullWidthElements);
811 auto originType = cast<VectorType>(fullWidthStorePart.getType());
813 auto storeType = VectorType::get(
814 {originType.getNumElements() / emulatedPerContainerElem},
816 auto bitCast = vector::BitCastOp::create(rewriter, loc, storeType,
818 vector::StoreOp::create(rewriter, loc, bitCast.getResult(), memrefBase,
821 currentSourceIndex += numNonFullWidthElements;
822 currentDestIndex = arith::AddIOp::create(
823 rewriter, loc, rewriter.getIndexType(), currentDestIndex,
830 auto remainingElements = origElements - currentSourceIndex;
831 if (remainingElements != 0) {
832 auto subWidthStorePart =
834 currentSourceIndex, remainingElements, 0);
837 auto maskValues = SmallVector<bool>(emulatedPerContainerElem,
false);
838 std::fill_n(maskValues.begin(), remainingElements, 1);
839 auto backMask = arith::ConstantOp::create(
843 storeFunc(rewriter, loc, memrefBase, currentDestIndex,
844 cast<VectorValue>(subWidthStorePart), backMask.getResult());
847 rewriter.eraseOp(op);
852 const bool disableAtomicRMW;
853 const bool assumeAligned;
867struct ConvertVectorMaskedStore final
868 : OpConversionPattern<vector::MaskedStoreOp> {
872 matchAndRewrite(vector::MaskedStoreOp op, OpAdaptor adaptor,
873 ConversionPatternRewriter &rewriter)
const override {
876 if (op.getValueToStore().getType().getRank() != 1)
877 return rewriter.notifyMatchFailure(
878 op,
"Memref in vector.maskedstore op must be flattened beforehand.");
880 auto loc = op.getLoc();
881 auto containerElemTy =
882 cast<MemRefType>(adaptor.getBase().getType()).getElementType();
883 Type emulatedElemTy = op.getValueToStore().getType().getElementType();
885 int containerBits = containerElemTy.getIntOrFloatBitWidth();
888 if (containerBits % emulatedBits != 0) {
889 return rewriter.notifyMatchFailure(
890 op,
"impossible to pack emulated elements into container elements "
891 "(bit-wise misalignment)");
894 int emulatedPerContainerElem = containerBits / emulatedBits;
895 int origElements = op.getValueToStore().getType().getNumElements();
896 if (origElements % emulatedPerContainerElem != 0)
899 auto stridedMetadata =
900 memref::ExtractStridedMetadataOp::create(rewriter, loc, op.getBase());
901 OpFoldResult linearizedIndicesOfr;
902 memref::LinearizedMemRefInfo linearizedInfo;
903 std::tie(linearizedInfo, linearizedIndicesOfr) =
905 rewriter, loc, emulatedBits, containerBits,
906 stridedMetadata.getConstifiedMixedOffset(),
907 stridedMetadata.getConstifiedMixedSizes(),
908 stridedMetadata.getConstifiedMixedStrides(),
910 Value linearizedIndices =
946 rewriter, loc, op.getMask(), origElements, emulatedPerContainerElem);
950 auto numElements = (origElements + emulatedPerContainerElem - 1) /
951 emulatedPerContainerElem;
952 auto newType = VectorType::get(numElements, containerElemTy);
953 auto passThru = arith::ConstantOp::create(rewriter, loc, newType,
954 rewriter.getZeroAttr(newType));
956 auto newLoad = vector::MaskedLoadOp::create(
957 rewriter, loc, newType, adaptor.getBase(), linearizedIndices,
958 newMask.value()->getResult(0), passThru);
960 auto newBitCastType =
961 VectorType::get(numElements * emulatedPerContainerElem, emulatedElemTy);
963 vector::BitCastOp::create(rewriter, loc, newBitCastType, newLoad);
964 valueToStore = arith::SelectOp::create(rewriter, loc, op.getMask(),
965 op.getValueToStore(), valueToStore);
967 vector::BitCastOp::create(rewriter, loc, newType, valueToStore);
969 rewriter.replaceOpWithNewOp<vector::MaskedStoreOp>(
970 op, adaptor.getBase(), linearizedIndices, newMask.value()->getResult(0),
991struct ConvertVectorLoad final : OpConversionPattern<vector::LoadOp> {
995 matchAndRewrite(vector::LoadOp op, OpAdaptor adaptor,
996 ConversionPatternRewriter &rewriter)
const override {
998 if (op.getVectorType().getRank() != 1)
999 return rewriter.notifyMatchFailure(
1000 op,
"Memref in emulated vector ops must be flattened beforehand.");
1002 auto loc = op.getLoc();
1003 auto containerElemTy =
1004 cast<MemRefType>(adaptor.getBase().getType()).getElementType();
1005 Type emulatedElemTy = op.getType().getElementType();
1007 int containerBits = containerElemTy.getIntOrFloatBitWidth();
1010 if (containerBits % emulatedBits != 0) {
1011 return rewriter.notifyMatchFailure(
1012 op,
"impossible to pack emulated elements into container elements "
1013 "(bit-wise misalignment)");
1015 int emulatedPerContainerElem = containerBits / emulatedBits;
1044 auto origElements = op.getVectorType().getNumElements();
1046 bool isDivisibleInSize = origElements % emulatedPerContainerElem == 0;
1048 auto stridedMetadata =
1049 memref::ExtractStridedMetadataOp::create(rewriter, loc, op.getBase());
1051 OpFoldResult linearizedIndices;
1052 memref::LinearizedMemRefInfo linearizedInfo;
1053 std::tie(linearizedInfo, linearizedIndices) =
1055 rewriter, loc, emulatedBits, containerBits,
1056 stridedMetadata.getConstifiedMixedOffset(),
1057 stridedMetadata.getConstifiedMixedSizes(),
1058 stridedMetadata.getConstifiedMixedStrides(),
1061 std::optional<int64_t> foldedIntraVectorOffset =
1062 isDivisibleInSize ? 0
1066 int64_t maxintraDataOffset =
1067 foldedIntraVectorOffset.value_or(emulatedPerContainerElem - 1);
1068 auto numElements = llvm::divideCeil(maxintraDataOffset + origElements,
1069 emulatedPerContainerElem);
1072 numElements, emulatedElemTy, containerElemTy);
1074 if (!foldedIntraVectorOffset) {
1075 auto resultVector = arith::ConstantOp::create(
1076 rewriter, loc, op.getType(), rewriter.getZeroAttr(op.getType()));
1080 }
else if (!isDivisibleInSize) {
1082 rewriter, loc,
result, *foldedIntraVectorOffset, origElements);
1084 rewriter.replaceOp(op,
result);
1099struct ConvertVectorMaskedLoad final
1100 : OpConversionPattern<vector::MaskedLoadOp> {
1104 matchAndRewrite(vector::MaskedLoadOp op, OpAdaptor adaptor,
1105 ConversionPatternRewriter &rewriter)
const override {
1106 if (op.getVectorType().getRank() != 1)
1107 return rewriter.notifyMatchFailure(
1108 op,
"Memref in emulated vector ops must be flattened beforehand.");
1110 auto loc = op.getLoc();
1112 auto containerElemTy =
1113 cast<MemRefType>(adaptor.getBase().getType()).getElementType();
1114 Type emulatedElemTy = op.getType().getElementType();
1116 int containerBits = containerElemTy.getIntOrFloatBitWidth();
1119 if (containerBits % emulatedBits != 0) {
1120 return rewriter.notifyMatchFailure(
1121 op,
"impossible to pack emulated elements into container elements "
1122 "(bit-wise misalignment)");
1124 int emulatedPerContainerElem = containerBits / emulatedBits;
1168 auto origType = op.getVectorType();
1169 auto origElements = origType.getNumElements();
1171 bool isDivisibleInSize = origElements % emulatedPerContainerElem == 0;
1173 auto stridedMetadata =
1174 memref::ExtractStridedMetadataOp::create(rewriter, loc, op.getBase());
1175 OpFoldResult linearizedIndices;
1176 memref::LinearizedMemRefInfo linearizedInfo;
1177 std::tie(linearizedInfo, linearizedIndices) =
1179 rewriter, loc, emulatedBits, containerBits,
1180 stridedMetadata.getConstifiedMixedOffset(),
1181 stridedMetadata.getConstifiedMixedSizes(),
1182 stridedMetadata.getConstifiedMixedStrides(),
1185 std::optional<int64_t> foldedIntraVectorOffset =
1186 isDivisibleInSize ? 0
1189 int64_t maxIntraDataOffset =
1190 foldedIntraVectorOffset.value_or(emulatedPerContainerElem - 1);
1191 FailureOr<Operation *> newMask =
1193 emulatedPerContainerElem, maxIntraDataOffset);
1197 Value passthru = op.getPassThru();
1199 auto numElements = llvm::divideCeil(maxIntraDataOffset + origElements,
1200 emulatedPerContainerElem);
1201 auto loadType = VectorType::get(numElements, containerElemTy);
1202 auto newBitcastType =
1203 VectorType::get(numElements * emulatedPerContainerElem, emulatedElemTy);
1205 auto emptyVector = arith::ConstantOp::create(
1206 rewriter, loc, newBitcastType, rewriter.getZeroAttr(newBitcastType));
1207 if (!foldedIntraVectorOffset) {
1211 }
else if (!isDivisibleInSize) {
1213 *foldedIntraVectorOffset);
1216 vector::BitCastOp::create(rewriter, loc, loadType, passthru);
1219 auto newLoad = vector::MaskedLoadOp::create(
1220 rewriter, loc, loadType, adaptor.getBase(),
1222 newMask.value()->getResult(0), newPassThru);
1227 vector::BitCastOp::create(rewriter, loc, newBitcastType, newLoad);
1229 Value mask = op.getMask();
1230 auto newSelectMaskType = VectorType::get(
1231 numElements * emulatedPerContainerElem, rewriter.getI1Type());
1234 arith::ConstantOp::create(rewriter, loc, newSelectMaskType,
1235 rewriter.getZeroAttr(newSelectMaskType));
1236 if (!foldedIntraVectorOffset) {
1240 }
else if (!isDivisibleInSize) {
1242 *foldedIntraVectorOffset);
1246 arith::SelectOp::create(rewriter, loc, mask, bitCast, passthru);
1247 if (!foldedIntraVectorOffset) {
1249 rewriter, loc,
result, op.getPassThru(),
1251 }
else if (!isDivisibleInSize) {
1253 rewriter, loc,
result, *foldedIntraVectorOffset, origElements);
1255 rewriter.replaceOp(op,
result);
1276static bool fitsInMultiByteContainerTy(VectorType subByteVecTy,
1277 Type multiByteScalarTy) {
1278 assert((isa<IntegerType, FloatType>(multiByteScalarTy)) &&
"Not scalar!");
1280 int subByteBits = subByteVecTy.getElementType().getIntOrFloatBitWidth();
1283 assert(subByteBits < 8 &&
"Not a sub-byte scalar type!");
1284 assert(multiByteBits % 8 == 0 &&
"Not a multi-byte scalar type!");
1285 assert(multiByteBits % subByteBits == 0 &&
"Unalagined element types!");
1287 int elemsPerMultiByte = multiByteBits / subByteBits;
1289 return subByteVecTy.getShape().back() % elemsPerMultiByte == 0;
1297struct ConvertVectorTransferRead final
1298 : OpConversionPattern<vector::TransferReadOp> {
1302 matchAndRewrite(vector::TransferReadOp op, OpAdaptor adaptor,
1303 ConversionPatternRewriter &rewriter)
const override {
1307 if (op.getVectorType().getRank() != 1)
1308 return rewriter.notifyMatchFailure(
1309 op,
"Memref in emulated vector ops must be flattened beforehand.");
1311 auto loc = op.getLoc();
1312 auto containerElemTy =
1313 cast<MemRefType>(adaptor.getBase().getType()).getElementType();
1314 Type emulatedElemTy = op.getType().getElementType();
1316 int containerBits = containerElemTy.getIntOrFloatBitWidth();
1319 if (containerBits % emulatedBits != 0) {
1320 return rewriter.notifyMatchFailure(
1321 op,
"impossible to pack emulated elements into container elements "
1322 "(bit-wise misalignment)");
1324 int emulatedPerContainerElem = containerBits / emulatedBits;
1326 auto origElements = op.getVectorType().getNumElements();
1329 bool isDivisibleInSize =
1330 fitsInMultiByteContainerTy(op.getVectorType(), containerElemTy);
1334 Value padding = adaptor.getPadding();
1336 padding = arith::BitcastOp::create(
1338 IntegerType::get(rewriter.getContext(),
1343 arith::ExtUIOp::create(rewriter, loc, containerElemTy, padding);
1345 auto stridedMetadata =
1346 memref::ExtractStridedMetadataOp::create(rewriter, loc, op.getBase());
1348 OpFoldResult linearizedIndices;
1349 memref::LinearizedMemRefInfo linearizedInfo;
1350 std::tie(linearizedInfo, linearizedIndices) =
1352 rewriter, loc, emulatedBits, containerBits,
1353 stridedMetadata.getConstifiedMixedOffset(),
1354 stridedMetadata.getConstifiedMixedSizes(),
1355 stridedMetadata.getConstifiedMixedStrides(),
1358 std::optional<int64_t> foldedIntraVectorOffset =
1359 isDivisibleInSize ? 0
1362 int64_t maxIntraDataOffset =
1363 foldedIntraVectorOffset.value_or(emulatedPerContainerElem - 1);
1364 auto numElements = llvm::divideCeil(maxIntraDataOffset + origElements,
1365 emulatedPerContainerElem);
1367 auto newRead = vector::TransferReadOp::create(
1368 rewriter, loc, VectorType::get(numElements, containerElemTy),
1373 auto bitCast = vector::BitCastOp::create(
1375 VectorType::get(numElements * emulatedPerContainerElem, emulatedElemTy),
1378 Value
result = bitCast->getResult(0);
1379 if (!foldedIntraVectorOffset) {
1380 auto zeros = arith::ConstantOp::create(
1381 rewriter, loc, op.getType(), rewriter.getZeroAttr(op.getType()));
1385 }
else if (!isDivisibleInSize) {
1387 rewriter, loc,
result, *foldedIntraVectorOffset, origElements);
1389 rewriter.replaceOp(op,
result);
1404struct SourceElementRange {
1406 int64_t sourceElementIdx;
1408 int64_t sourceBitBegin;
1409 int64_t sourceBitEnd;
1412struct SourceElementRangeList :
public SmallVector<SourceElementRange> {
1418 int64_t computeLeftShiftAmount(int64_t shuffleIdx)
const {
1420 for (int64_t i = 0; i < shuffleIdx; ++i)
1421 res += (*
this)[i].sourceBitEnd - (*this)[i].sourceBitBegin;
1440struct BitCastBitsEnumerator {
1441 BitCastBitsEnumerator(VectorType sourceVectorType,
1442 VectorType targetVectorType);
1444 int64_t getMaxNumberOfEntries() {
1445 int64_t numVectors = 0;
1446 for (
const auto &l : sourceElementRanges)
1447 numVectors = std::max(numVectors, (int64_t)l.size());
1451 VectorType sourceVectorType;
1452 VectorType targetVectorType;
1453 SmallVector<SourceElementRangeList> sourceElementRanges;
1527struct BitCastRewriter {
1530 SmallVector<int64_t> shuffles;
1531 SmallVector<Attribute> masks, shiftRightAmounts, shiftLeftAmounts;
1534 BitCastRewriter(VectorType sourceVectorType, VectorType targetVectorType);
1537 LogicalResult commonPrecondition(PatternRewriter &rewriter,
1538 VectorType preconditionType, Operation *op);
1541 SmallVector<BitCastRewriter::Metadata>
1542 precomputeMetadata(IntegerType shuffledElementType);
1546 Value genericRewriteStep(PatternRewriter &rewriter, Location loc,
1547 Value initialValue, Value runningResult,
1548 const BitCastRewriter::Metadata &metadata);
1553 BitCastBitsEnumerator enumerator;
1560 for (
const auto &l : vec) {
1561 for (
auto it : llvm::enumerate(l)) {
1562 os <<
"{ " << it.value().sourceElementIdx <<
": b@["
1563 << it.value().sourceBitBegin <<
".." << it.value().sourceBitEnd
1564 <<
") lshl: " << l.computeLeftShiftAmount(it.index()) <<
" } ";
1571BitCastBitsEnumerator::BitCastBitsEnumerator(VectorType sourceVectorType,
1572 VectorType targetVectorType)
1573 : sourceVectorType(sourceVectorType), targetVectorType(targetVectorType) {
1575 assert(sourceVectorType.getRank() == 1 && !sourceVectorType.isScalable() &&
1576 "requires -D non-scalable vector type");
1577 assert(targetVectorType.getRank() == 1 && !targetVectorType.isScalable() &&
1578 "requires -D non-scalable vector type");
1579 int64_t sourceBitWidth = sourceVectorType.getElementTypeBitWidth();
1580 int64_t mostMinorSourceDim = sourceVectorType.getShape().back();
1581 LDBG() <<
"sourceVectorType: " << sourceVectorType;
1583 int64_t targetBitWidth = targetVectorType.getElementTypeBitWidth();
1584 int64_t mostMinorTargetDim = targetVectorType.getShape().back();
1585 LDBG() <<
"targetVectorType: " << targetVectorType;
1587 int64_t bitwidth = targetBitWidth * mostMinorTargetDim;
1588 (
void)mostMinorSourceDim;
1589 assert(bitwidth == sourceBitWidth * mostMinorSourceDim &&
1590 "source and target bitwidths must match");
1594 for (
int64_t resultBit = 0; resultBit < bitwidth;) {
1595 int64_t resultElement = resultBit / targetBitWidth;
1596 int64_t resultBitInElement = resultBit % targetBitWidth;
1597 int64_t sourceElementIdx = resultBit / sourceBitWidth;
1598 int64_t sourceBitInElement = resultBit % sourceBitWidth;
1599 int64_t step = std::min(sourceBitWidth - sourceBitInElement,
1600 targetBitWidth - resultBitInElement);
1601 sourceElementRanges[resultElement].push_back(
1602 {sourceElementIdx, sourceBitInElement, sourceBitInElement + step});
1607BitCastRewriter::BitCastRewriter(VectorType sourceVectorType,
1608 VectorType targetVectorType)
1609 : enumerator(BitCastBitsEnumerator(sourceVectorType, targetVectorType)) {
1610 LDBG() <<
"\n" << enumerator.sourceElementRanges;
1616 VectorType preconditionType,
1618 if (!preconditionType || preconditionType.isScalable())
1623 unsigned bitwidth = preconditionType.getElementTypeBitWidth();
1624 if (bitwidth % 8 != 0)
1630LogicalResult BitCastRewriter::commonPrecondition(
PatternRewriter &rewriter,
1631 VectorType preconditionType,
1633 if (!enumerator.sourceVectorType || !enumerator.targetVectorType)
1636 if (!preconditionType || preconditionType.getRank() != 1)
1674 VectorType subByteVecTy,
1678 "container element type is not a scalar");
1685 unsigned subByteBits = subByteVecTy.getElementTypeBitWidth();
1689 assert(containerBits % 8 == 0 &&
"Not a multi-byte scalar type!");
1692 if (subByteBits != 2 && subByteBits != 4)
1694 op,
"only 2-bit and 4-bit sub-byte type is supported at this moment");
1697 if (containerBits % subByteBits != 0)
1701 if (!fitsInMultiByteContainerTy(subByteVecTy, containerTy))
1703 op,
"not possible to fit this sub-byte vector type into a vector of "
1704 "the given multi-byte type");
1709SmallVector<BitCastRewriter::Metadata>
1710BitCastRewriter::precomputeMetadata(IntegerType shuffledElementType) {
1711 SmallVector<BitCastRewriter::Metadata>
result;
1712 for (int64_t shuffleIdx = 0, e = enumerator.getMaxNumberOfEntries();
1713 shuffleIdx < e; ++shuffleIdx) {
1714 SmallVector<int64_t> shuffles;
1715 SmallVector<Attribute> masks, shiftRightAmounts, shiftLeftAmounts;
1718 for (
auto &srcEltRangeList : enumerator.sourceElementRanges) {
1719 int64_t sourceElement = (shuffleIdx < (int64_t)srcEltRangeList.size())
1720 ? srcEltRangeList[shuffleIdx].sourceElementIdx
1722 shuffles.push_back(sourceElement);
1724 int64_t bitLo = (shuffleIdx < (int64_t)srcEltRangeList.size())
1725 ? srcEltRangeList[shuffleIdx].sourceBitBegin
1727 int64_t bitHi = (shuffleIdx < (int64_t)srcEltRangeList.size())
1728 ? srcEltRangeList[shuffleIdx].sourceBitEnd
1730 IntegerAttr mask = IntegerAttr::get(
1731 shuffledElementType,
1732 llvm::APInt::getBitsSet(shuffledElementType.getIntOrFloatBitWidth(),
1734 masks.push_back(mask);
1736 int64_t shiftRight = bitLo;
1737 shiftRightAmounts.push_back(
1738 IntegerAttr::get(shuffledElementType, shiftRight));
1740 int64_t shiftLeft = srcEltRangeList.computeLeftShiftAmount(shuffleIdx);
1741 shiftLeftAmounts.push_back(
1742 IntegerAttr::get(shuffledElementType, shiftLeft));
1745 result.push_back({shuffles, masks, shiftRightAmounts, shiftLeftAmounts});
1750Value BitCastRewriter::genericRewriteStep(
1751 PatternRewriter &rewriter, Location loc, Value initialValue,
1752 Value runningResult,
const BitCastRewriter::Metadata &metadata) {
1754 auto shuffleOp = vector::ShuffleOp::create(rewriter, loc, initialValue,
1755 initialValue, metadata.shuffles);
1758 VectorType shuffledVectorType = shuffleOp.getResultVectorType();
1759 auto constOp = arith::ConstantOp::create(
1762 Value andValue = arith::AndIOp::create(rewriter, loc, shuffleOp, constOp);
1765 auto shiftRightConstantOp = arith::ConstantOp::create(
1768 Value shiftedRight =
1769 arith::ShRUIOp::create(rewriter, loc, andValue, shiftRightConstantOp);
1772 auto shiftLeftConstantOp = arith::ConstantOp::create(
1776 arith::ShLIOp::create(rewriter, loc, shiftedRight, shiftLeftConstantOp);
1780 ? arith::OrIOp::create(rewriter, loc, runningResult, shiftedLeft)
1783 return runningResult;
1794 auto srcVecType = cast<VectorType>(subByteVec.
getType());
1795 int64_t srcBitwidth = srcVecType.getElementType().getIntOrFloatBitWidth();
1796 assert(8 % srcBitwidth == 0 &&
1797 "Unsupported sub-byte type (not a divisor of i8)");
1798 int64_t numSrcElemsPerByte = 8 / srcBitwidth;
1801 vecShape.back() = vecShape.back() / numSrcElemsPerByte;
1802 auto i8VecType = VectorType::get(vecShape, rewriter.
getI8Type());
1803 return vector::BitCastOp::create(rewriter, loc, i8VecType, subByteVec);
1824 int bitIdx,
int numBits) {
1825 auto srcType = cast<VectorType>(src.
getType());
1827 int8_t bitsToShiftLeft = 8 - numBits - bitIdx;
1828 assert(bitIdx >= 0 && bitsToShiftLeft >= 0 && numBits > 0 && numBits <= 8 &&
1829 "Invalid bitIdx range");
1830 if (bitsToShiftLeft != 0) {
1831 Value shiftLeftValues = arith::ConstantOp::create(
1833 shl = arith::ShLIOp::create(rewriter, loc, src, shiftLeftValues);
1836 int8_t bitsToShiftRight = 8 - numBits;
1837 Value shiftRightValues = arith::ConstantOp::create(
1839 Value shr = arith::ShRSIOp::create(rewriter, loc, shl, shiftRightValues);
1866 int bitIdx,
int numBits) {
1867 assert(bitIdx >= 0 && bitIdx <= 8 - numBits && numBits > 0 && numBits <= 8 &&
1868 "Invalid bitIdx range");
1869 auto srcType = cast<VectorType>(src.
getType());
1870 int8_t bitsToShiftRight = bitIdx;
1872 if (bitsToShiftRight != 0) {
1873 Value shiftRightValues = arith::ConstantOp::create(
1875 shr = arith::ShRUIOp::create(rewriter, loc, src, shiftRightValues);
1877 if (bitIdx + numBits == 8) {
1880 uint8_t lowBitsMask = (1 << numBits) - 1;
1881 Value lowBitsMaskValues = arith::ConstantOp::create(
1883 return arith::AndIOp::create(rewriter, loc, shr, lowBitsMaskValues);
1893 [[maybe_unused]]
auto srcVecType = cast<VectorType>(srcValue.
getType());
1894 assert(srcVecType.getElementType().isSignlessInteger(4) &&
1895 "Expected i4 type");
1902 Value low = extFn(rewriter, loc, i8Vector, 0, 4);
1903 Value high = extFn(rewriter, loc, i8Vector, 4, 4);
1906 return vector::InterleaveOp::create(rewriter, loc, low, high);
1913 [[maybe_unused]] VectorType srcVecType = cast<VectorType>(srcValue.
getType());
1914 assert(srcVecType.getElementType().isSignlessInteger(2) &&
1915 "Expected i2 type");
1922 Value vec0 = extFn(rewriter, loc, i8Vector, 0, 2);
1924 Value vec1 = extFn(rewriter, loc, i8Vector, 2, 2);
1926 Value vec2 = extFn(rewriter, loc, i8Vector, 4, 2);
1928 Value vec3 = extFn(rewriter, loc, i8Vector, 6, 2);
1939 Value interleave02 = vector::InterleaveOp::create(rewriter, loc, vec0, vec2);
1940 Value interleave13 = vector::InterleaveOp::create(rewriter, loc, vec1, vec3);
1941 return vector::InterleaveOp::create(rewriter, loc, interleave02,
1949 VectorType srcVecType = cast<VectorType>(srcValue.
getType());
1950 assert(srcVecType.getElementType().isSignlessInteger(8) &&
1951 "Expected i8 type");
1954 auto deinterleaveOp = vector::DeinterleaveOp::create(rewriter, loc, srcValue);
1957 constexpr int8_t i8LowBitMask = 0x0F;
1958 VectorType deinterI8VecType = deinterleaveOp.getResultVectorType();
1959 Value zeroOutMask = arith::ConstantOp::create(
1961 Value zeroOutLow = arith::AndIOp::create(
1962 rewriter, loc, deinterleaveOp.getRes1(), zeroOutMask);
1965 constexpr int8_t bitsToShift = 4;
1966 auto shiftValues = arith::ConstantOp::create(
1968 Value shlHigh = arith::ShLIOp::create(rewriter, loc, deinterleaveOp.getRes2(),
1972 auto mergedHiLowOp = arith::OrIOp::create(rewriter, loc, zeroOutLow, shlHigh);
1975 auto i4VecType = srcVecType.cloneWith(std::nullopt, rewriter.
getI4Type());
1976 return vector::BitCastOp::create(rewriter, loc, i4VecType, mergedHiLowOp);
1983struct RewriteBitCastOfTruncI : OpRewritePattern<vector::BitCastOp> {
1986 LogicalResult matchAndRewrite(vector::BitCastOp bitCastOp,
1987 PatternRewriter &rewriter)
const override {
1990 bitCastOp.getSource().template getDefiningOp<arith::TruncIOp>();
1995 VectorType sourceVectorType = bitCastOp.getSourceVectorType();
1996 VectorType targetVectorType = bitCastOp.getResultVectorType();
1997 BitCastRewriter bcr(sourceVectorType, targetVectorType);
1998 if (
failed(bcr.commonPrecondition(rewriter, targetVectorType, bitCastOp)))
2002 Value truncValue = truncOp.getIn();
2003 auto shuffledElementType =
2005 Value runningResult;
2006 for (
const BitCastRewriter ::Metadata &metadata :
2007 bcr.precomputeMetadata(shuffledElementType)) {
2008 runningResult = bcr.genericRewriteStep(
2009 rewriter, bitCastOp->getLoc(), truncValue, runningResult, metadata);
2013 bool narrowing = targetVectorType.getElementTypeBitWidth() <=
2014 shuffledElementType.getIntOrFloatBitWidth();
2016 if (runningResult.
getType() == bitCastOp.getResultVectorType()) {
2017 rewriter.
replaceOp(bitCastOp, runningResult);
2020 bitCastOp, bitCastOp.getResultVectorType(), runningResult);
2023 if (runningResult.
getType() == bitCastOp.getResultVectorType()) {
2024 rewriter.
replaceOp(bitCastOp, runningResult);
2027 bitCastOp, bitCastOp.getResultVectorType(), runningResult);
2044template <
typename ExtOpType>
2045struct RewriteExtOfBitCast : OpRewritePattern<ExtOpType> {
2046 using OpRewritePattern<ExtOpType>::OpRewritePattern;
2048 RewriteExtOfBitCast(MLIRContext *context, PatternBenefit benefit)
2049 : OpRewritePattern<ExtOpType>(context, benefit) {}
2051 LogicalResult matchAndRewrite(ExtOpType extOp,
2052 PatternRewriter &rewriter)
const override {
2054 auto bitCastOp = extOp.getIn().template getDefiningOp<vector::BitCastOp>();
2059 VectorType sourceVectorType = bitCastOp.getSourceVectorType();
2060 VectorType targetVectorType = bitCastOp.getResultVectorType();
2061 BitCastRewriter bcr(sourceVectorType, targetVectorType);
2062 if (
failed(bcr.commonPrecondition(
2063 rewriter, cast<VectorType>(extOp.getOut().getType()), bitCastOp)))
2067 Value runningResult;
2068 Value sourceValue = bitCastOp.getSource();
2069 auto shuffledElementType =
2071 for (
const BitCastRewriter::Metadata &metadata :
2072 bcr.precomputeMetadata(shuffledElementType)) {
2073 runningResult = bcr.genericRewriteStep(
2074 rewriter, bitCastOp->getLoc(), sourceValue, runningResult, metadata);
2079 cast<VectorType>(extOp.getOut().getType()).getElementTypeBitWidth() <=
2080 shuffledElementType.getIntOrFloatBitWidth();
2083 extOp, cast<VectorType>(extOp.getOut().getType()), runningResult);
2086 extOp, cast<VectorType>(extOp.getOut().getType()), runningResult);
2127template <
typename ConversionOpType,
bool isSigned>
2128struct RewriteAlignedSubByteIntExt : OpRewritePattern<ConversionOpType> {
2129 using OpRewritePattern<ConversionOpType>::OpRewritePattern;
2131 LogicalResult matchAndRewrite(ConversionOpType conversionOp,
2132 PatternRewriter &rewriter)
const override {
2134 Value srcValue = conversionOp.getIn();
2135 VectorType srcVecType = dyn_cast<VectorType>(srcValue.
getType());
2136 VectorType dstVecType = dyn_cast<VectorType>(conversionOp.getType());
2144 rewriter, srcVecType,
2149 Location loc = conversionOp.getLoc();
2153 switch (srcVecType.getElementType().getIntOrFloatBitWidth()) {
2167 if (subByteExt.
getType() == conversionOp.getType())
2168 rewriter.
replaceOp(conversionOp, subByteExt);
2171 conversionOp, conversionOp.getType(), subByteExt);
2193struct RewriteAlignedSubByteIntTrunc : OpRewritePattern<arith::TruncIOp> {
2196 LogicalResult matchAndRewrite(arith::TruncIOp truncOp,
2197 PatternRewriter &rewriter)
const override {
2199 Value srcValue = truncOp.getIn();
2200 auto srcVecType = dyn_cast<VectorType>(srcValue.
getType());
2201 auto dstVecType = dyn_cast<VectorType>(truncOp.getType());
2202 if (!srcVecType || !dstVecType)
2209 if (dstVecType.getElementType().getIntOrFloatBitWidth() == 2)
2215 rewriter, dstVecType,
2220 Location loc = truncOp.getLoc();
2221 auto i8VecType = srcVecType.cloneWith(std::nullopt, rewriter.
getI8Type());
2223 srcVecType == i8VecType
2225 : arith::TruncIOp::create(rewriter, loc, i8VecType, srcValue);
2231 rewriter.
replaceOp(truncOp, subByteTrunc);
2248struct RewriteVectorTranspose : OpRewritePattern<vector::TransposeOp> {
2251 RewriteVectorTranspose(MLIRContext *context, PatternBenefit benefit)
2252 : OpRewritePattern<vector::TransposeOp>(context, benefit) {}
2254 LogicalResult matchAndRewrite(vector::TransposeOp transposeOp,
2255 PatternRewriter &rewriter)
const override {
2257 constexpr unsigned minNativeBitwidth = 8;
2258 VectorType srcSubByteVecType = transposeOp.getSourceVectorType();
2259 if (!srcSubByteVecType.getElementType().isSignlessInteger() ||
2260 srcSubByteVecType.getElementTypeBitWidth() >= minNativeBitwidth) {
2262 "not a sub-byte transpose");
2266 Location loc = transposeOp.getLoc();
2271 auto srcNativeVecType = srcSubByteVecType.cloneWith(
2273 Value extOp = arith::ExtSIOp::create(rewriter, loc, srcNativeVecType,
2274 transposeOp.getVector());
2275 Value newTranspose = vector::TransposeOp::create(
2276 rewriter, loc, extOp, transposeOp.getPermutation());
2277 VectorType dstSubByteVecType = transposeOp.getResultVectorType();
2291void vector::populateVectorNarrowTypeEmulationPatterns(
2292 const arith::NarrowTypeEmulationConverter &typeConverter,
2293 RewritePatternSet &patterns,
bool disableAtomicRMW,
bool assumeAligned) {
2296 patterns.
add<ConvertVectorLoad, ConvertVectorMaskedLoad,
2297 ConvertVectorMaskedStore, ConvertVectorTransferRead>(
2303 patterns.
insert<ConvertVectorStore>(patterns.
getContext(), disableAtomicRMW,
2307void vector::populateVectorNarrowTypeRewritePatterns(
2308 RewritePatternSet &patterns, PatternBenefit benefit) {
2310 patterns.
add<RewriteBitCastOfTruncI, RewriteExtOfBitCast<arith::ExtUIOp>,
2311 RewriteExtOfBitCast<arith::ExtSIOp>>(patterns.
getContext(),
2317 patterns.
add<RewriteAlignedSubByteIntExt<arith::ExtSIOp,
true>,
2318 RewriteAlignedSubByteIntExt<arith::SIToFPOp,
true>,
2319 RewriteAlignedSubByteIntTrunc>(patterns.
getContext(),
2323 .
add<RewriteAlignedSubByteIntExt<arith::ExtUIOp,
false>,
2324 RewriteAlignedSubByteIntExt<arith::UIToFPOp,
false>>(
2329void vector::populateVectorTransposeNarrowTypeRewritePatterns(
2330 RewritePatternSet &patterns, PatternBenefit benefit) {
2331 patterns.
add<RewriteVectorTranspose>(patterns.
getContext(), benefit);
2334void vector::populateMemRefFlattenAndVectorNarrowTypeEmulationPatterns(
2335 arith::NarrowTypeEmulationConverter &typeConverter,
2336 RewritePatternSet &patterns) {
2338 vector::populateVectorNarrowTypeEmulationPatterns(typeConverter, patterns);
static Type getElementType(Type type)
Determine the element type of type.
static Value extractSliceIntoByte(ConversionPatternRewriter &rewriter, Location loc, VectorValue vector, int64_t extractOffset, int64_t sliceNumElements, int64_t insertOffset)
Extract sliceNumElements from source vector at extractOffset, and insert it into an empty vector at i...
static Value rewriteI8ToI4Trunc(PatternRewriter &rewriter, Location loc, Value srcValue)
Rewrite the i8 -> i4 truncation into a deinterleave and series of bitwise ops to avoid leaving LLVM t...
std::function< Value(PatternRewriter &, Location, Value, int, int)> ExtractNBitsFn
TypedValue< MemRefType > MemRefValue
static VectorValue emulatedVectorLoad(OpBuilder &rewriter, Location loc, Value base, OpFoldResult linearizedIndices, int64_t numContainerElemsToLoad, Type emulatedElemTy, Type containerElemTy)
Emulate a vector load for emulatedElemTy using containerElemTy
TypedValue< VectorType > VectorValue
static FailureOr< Operation * > getCompressedMaskOp(OpBuilder &rewriter, Location loc, Value mask, int numSrcElems, int numSrcElemsPerDest, int numFrontPadElems=0)
Returns a compressed mask for the emulated vector.
static Value downcastSelectAndUpcast(OpBuilder &builder, Location loc, VectorType downcastType, VectorType upcastType, Value mask, Value trueValue, Value falseValue)
Downcast two values to downcastType, then select values based on mask, and casts the result to upcast...
static Value rewriteI4ToI8Ext(PatternRewriter &rewriter, Location loc, Value srcValue, const ExtractNBitsFn &extFn)
Rewrite the i4 -> i8 extension into a sequence of shuffles and bitwise ops to avoid leaving LLVM to s...
static Value dynamicallyInsertSubVector(RewriterBase &rewriter, Location loc, Value src, Value dest, OpFoldResult offset, int64_t numElemsToInsert)
Inserts 1-D subvector into a 1-D vector.
static Value staticallyInsertSubvector(OpBuilder &rewriter, Location loc, Value src, Value dest, int64_t offset)
Inserts 1-D subvector into a 1-D vector.
static void atomicRMW(OpBuilder &builder, Location loc, MemRefValue linearizedMemref, Value storeIdx, VectorValue valueToStore, Value mask)
Emits memref.generic_atomic_rmw op to store a subbyte-sized value to a byte in linearizedMemref,...
static Value staticallyExtractSubvector(OpBuilder &rewriter, Location loc, Value src, int64_t offset, int64_t numElemsToExtract)
Extracts 1-D subvector from a 1-D vector.
static LogicalResult commonConversionPrecondition(PatternRewriter &rewriter, VectorType preconditionType, Operation *op)
Verify that the precondition type meets the common preconditions for any conversion.
static Value dynamicallyExtractSubVector(OpBuilder &rewriter, Location loc, Value src, Value dest, OpFoldResult offset, int64_t numElemsToExtract)
Extracts 1-D subvector from a 1-D vector.
static LogicalResult alignedConversionPrecondition(PatternRewriter &rewriter, VectorType subByteVecTy, Type containerTy, Operation *op)
Verify that subByteVecTy (vector) and containerTy (scalar) are aligned.
static void nonAtomicRMW(OpBuilder &builder, Location loc, MemRefValue linearizedMemref, Value linearizedIndex, VectorValue valueToStore, Value mask)
Generate a non-atomic read-modify-write sequence for storing to the emulated type.
static Value bitcastSubByteVectorToI8(PatternRewriter &rewriter, Location loc, Value subByteVec)
Bitcasts the aligned subByteVec vector to a vector of i8.
static Value extractNBitsPerByteAndExtendToI8(PatternRewriter &rewriter, Location loc, Value src, int bitIdx, int numBits)
Extracts an unsigned N-bit sequence from each element of a vector of bytes, starting at the specified...
static Value rewriteI2ToI8Ext(PatternRewriter &rewriter, Location loc, Value srcValue, const ExtractNBitsFn &extFn)
Rewrite the i2 -> i8 extension into a sequence of shuffles and bitwise ops to avoid leaving LLVM to s...
static Value extractNBitsPerByteAndSignExtendToI8(PatternRewriter &rewriter, Location loc, Value src, int bitIdx, int numBits)
Extracts a signed N-bit sequence from each element of a vector of bytes, starting at the specified bi...
Base type for affine expression.
IntegerType getIntegerType(unsigned width)
MLIRContext * getContext() const
ArrayAttr getI64ArrayAttr(ArrayRef< int64_t > 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...
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
This class represents a single result from folding an operation.
This class implements the operand iterators for the Operation class.
Operation is the basic unit of execution within MLIR.
result_type_range getResultTypes()
unsigned short getBenefit() const
If the corresponding pattern can match, return its benefit. If the.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
RewritePatternSet & insert(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
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.
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
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...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isInteger() const
Return true if this is an integer type (with the specified width).
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
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 ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
OpFoldResult makeComposedFoldedAffineApply(OpBuilder &b, Location loc, AffineMap map, ArrayRef< OpFoldResult > operands, bool composeAffineMin=false)
Constructs an AffineApplyOp that applies map to operands after composing the map with the maps of any...
std::pair< LinearizedMemRefInfo, OpFoldResult > getLinearizedMemRefOffsetAndSize(OpBuilder &builder, Location loc, int srcBits, int dstBits, OpFoldResult offset, ArrayRef< OpFoldResult > sizes, ArrayRef< OpFoldResult > strides, ArrayRef< OpFoldResult > indices={}, LinearizedDivKind sizeDivKind=LinearizedDivKind::Floor)
void populateFlattenMemrefsPatterns(RewritePatternSet &patterns)
Patterns for flattening all supported multi-dimensional memref operations into one-dimensional memref...
Value constantOne(OpBuilder &builder, Location loc, Type tp)
Generates a 1-valued constant of the given type.
Include the generated interface declarations.
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
void bindSymbols(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to SymbolExpr at positions: [0 .
llvm::TypeSwitch< T, ResultT > TypeSwitch
Value getValueOrCreateConstantIndexOp(OpBuilder &b, Location loc, OpFoldResult ofr)
Converts an OpFoldResult to a Value.
OpFoldResult getAsOpFoldResult(Value val)
Given a value, try to extract a constant Attribute.
OpFoldResult intraDataOffset
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.