17#include "llvm/ADT/TypeSwitch.h"
18#include "llvm/Support/Debug.h"
25void XeGPUDialect::initialize() {
27#define GET_TYPEDEF_LIST
28#include <mlir/Dialect/XeGPU/IR/XeGPUTypes.cpp.inc>
32#include <mlir/Dialect/XeGPU/IR/XeGPU.cpp.inc>
35#define GET_ATTRDEF_LIST
36#include <mlir/Dialect/XeGPU/IR/XeGPUAttrs.cpp.inc>
48static SmallVector<SmallVector<Value>>
57 llvm::zip_equal(srcShape,
59 [](
const auto &t) {
return std::min(std::get<0>(t), std::get<1>(t)); });
63 llvm::zip(delinearizedId, subShape), [&](
const auto &t) ->
Value {
79 llvm::map_to_vector(llvm::zip_equal(base, distUnitLocalOffset),
80 [&](
const auto &t) ->
Value {
82 loc, std::get<0>(t), std::get<1>(t));
86 llvm::zip_equal(adds, srcShape), [&](
const auto &t) ->
Value {
92 coordinates.push_back(mods);
100 xegpu::DistributeLayoutAttr attr) {
101 assert(attr &&
"Layout attribute is missing.");
118 if (layout.size() !=
shape.size())
121 if (ratio.has_value()) {
122 newShape = ratio.value();
130 if (data.size() != shape.size())
133 if (!ratio.has_value() && rr)
135 if (!ratio.has_value())
145 auto maybeSgShape = tryDistribute(shape, attr.getEffectiveSgLayoutAsInt(),
146 attr.getEffectiveSgDataAsInt());
149 auto sgShape = maybeSgShape.value();
152 auto maybeInstShape =
153 tryDistribute(sgShape, {}, attr.getEffectiveInstDataAsInt(),
false);
156 auto instShape = maybeInstShape.value();
159 auto maybeLaneShape =
160 tryDistribute(instShape, attr.getEffectiveLaneLayoutAsInt(),
161 attr.getEffectiveLaneDataAsInt(),
false);
162 return maybeLaneShape.has_value();
168BlockTensorDescAttr BlockTensorDescAttr::get(mlir::MLIRContext *context,
169 xegpu::MemorySpace memory_space,
171 bool boundary_check) {
172 auto scopeAttr = MemorySpaceAttr::get(context, memory_space);
174 IntegerAttr::get(IntegerType::get(context, 64), array_length);
176 return Base::get(context, scopeAttr, lengthAttr, boundaryAttr);
179bool BlockTensorDescAttr::hasDefaultsOnly() {
180 return getMemorySpace().getValue() == xegpu::MemorySpace::Global &&
181 getArrayLength().getInt() == 1 && getBoundaryCheck().getValue();
188ScatterTensorDescAttr::get(mlir::MLIRContext *context,
189 xegpu::MemorySpace memory_space,
int chunk_size) {
190 auto scopeAttr = MemorySpaceAttr::get(context, memory_space);
192 IntegerAttr::get(IntegerType::get(context, 64), chunk_size);
193 return Base::get(context, scopeAttr, chunkSizeAttr);
196LogicalResult ScatterTensorDescAttr::verify(
197 llvm::function_ref<mlir::InFlightDiagnostic()>
emitError,
198 MemorySpaceAttr memory_space, IntegerAttr chunk_size) {
199 int64_t chunkSize = chunk_size.getInt();
201 return emitError() <<
"invalid chunk size";
210LayoutAttr::verify(llvm::function_ref<mlir::InFlightDiagnostic()>
emitError,
218 if (!sg_layout && !inst_data && !lane_layout) {
220 <<
"expected at least one of sg_layout, inst_data or lane_layout";
226 if (sg_layout && inst_data && sg_layout.size() != inst_data.size()) {
228 <<
"expected sg_layout and inst_data to have the same rank";
231 if (sg_layout && lane_layout && sg_layout.size() != lane_layout.size()) {
233 <<
"expected sg_layout and lane_layout to have the same rank";
236 if (inst_data && lane_layout && inst_data.size() != lane_layout.size()) {
237 return emitError() <<
"expected inst_data and lane_layout to have the same "
238 "rank, got inst_data "
239 << inst_data.size() <<
", lane_layout "
240 << lane_layout.size();
247 return emitError() <<
"expected sg_layout being used with sg_data";
248 if (sg_data.size() != sg_layout.size())
250 <<
"expected sg_data and sg_layout to have the same rank";
257 return emitError() <<
"expected lane_layout being used with lane_data";
258 if (lane_data.size() != lane_layout.size())
260 <<
"expected lane_data and lane_layout to have the same rank";
264 if (!sg_layout && !lane_layout)
266 <<
"expected sg_layout/lane_layout being used with order";
268 if (sg_layout && order.size() != sg_layout.size())
270 <<
"expected order and sg_layout to have the same rank";
272 if (lane_layout && order.size() != lane_layout.size())
274 <<
"expected order and lane_layout to have the same rank";
280FailureOr<SmallVector<Value>>
281LayoutAttr::delinearizeId(OpBuilder &builder, Location loc, Value linearId) {
283 SmallVector<int64_t> sgLayoutInt;
284 if (isForWorkgroup()) {
285 sgLayoutInt = getEffectiveSgLayoutAsInt();
286 }
else if (isForSubgroup()) {
287 sgLayoutInt = getEffectiveLaneLayoutAsInt();
295 SmallVector<int64_t> order;
296 if (orderAttr && !orderAttr.empty()) {
297 order = llvm::to_vector(
299 [](int32_t idx) { return static_cast<int64_t>(idx); }));
302 order = llvm::to_vector(
303 llvm::reverse(llvm::seq<int64_t>(0, sgLayoutInt.size())));
306 if (order.size() != sgLayoutInt.size()) {
310 SmallVector<Value>
result(sgLayoutInt.size());
311 Value remaining = linearId;
334 for (
size_t i = 0; i < order.size(); ++i) {
335 int64_t dimIdx = order[i];
336 int64_t dimSize = sgLayoutInt[dimIdx];
339 builder.
createOrFold<arith::ConstantIndexOp>(loc, dimSize);
346 builder.
createOrFold<index::RemUOp>(loc, remaining, dimSizeVal);
353 if (i < order.size() - 1) {
355 builder.
createOrFold<index::DivUOp>(loc, remaining, dimSizeVal);
364FailureOr<SmallVector<SmallVector<Value>>>
365LayoutAttr::computeDistributedCoords(OpBuilder &builder, Location loc,
366 Value linearId, ArrayRef<int64_t> shape) {
367 SmallVector<int64_t> layout;
368 SmallVector<int64_t> subShape;
369 if (isForWorkgroup()) {
370 layout = getEffectiveSgLayoutAsInt();
371 subShape = getEffectiveSgDataAsInt();
372 }
else if (isForSubgroup()) {
373 layout = getEffectiveLaneLayoutAsInt();
374 subShape = getEffectiveLaneDataAsInt();
378 if (subShape.empty()) {
380 subShape = derivedShape.value();
386 auto maybeIds = delinearizeId(builder, loc, linearId);
389 SmallVector<Value> ids = *maybeIds;
391 return genCoordinates(builder, loc, ids, layout, subShape, shape);
398SliceAttr::verify(llvm::function_ref<InFlightDiagnostic()>
emitError,
400 if (!parent || !dims)
401 return emitError() <<
"expected parent layout and dims attribute";
403 int64_t rank = parent.getRank();
406 llvm::SmallDenseSet<int64_t> seen;
408 if (dim < 0 || dim >= rank)
409 return emitError() <<
"invalid dim (" << dim <<
") in slice attribute.";
410 if (!seen.insert(dim).second)
411 return emitError() <<
"repeated dim (" << dim <<
") in slice attribute.";
416SliceAttr SliceAttr::flatten()
const {
417 xegpu::DistributeLayoutAttr parent = getParent();
418 SmallVector<DenseI64ArrayAttr> slicedDims({
getDims()});
420 while (
auto sliceAttr = dyn_cast<xegpu::SliceAttr>(parent)) {
421 parent = sliceAttr.getParent();
422 slicedDims.push_back(sliceAttr.getDims());
425 auto layoutAttr = dyn_cast<xegpu::LayoutAttr>(parent);
427 llvm::to_vector(llvm::seq<int64_t>(0, layoutAttr.getRank()));
430 SmallVector<int64_t> remainingDims(
indices);
431 for (
auto dim : llvm::reverse(slicedDims))
432 remainingDims = XeGPUDialect::slice(llvm::ArrayRef<int64_t>(remainingDims),
436 SmallVector<int64_t> flattendDims = XeGPUDialect::slice(
437 llvm::ArrayRef<int64_t>(
indices), llvm::ArrayRef<int64_t>(remainingDims));
439 return xegpu::SliceAttr::get(
444FailureOr<SmallVector<Value>>
445SliceAttr::delinearizeId(OpBuilder &builder, Location loc, Value linearId) {
446 SliceAttr attr = flatten();
447 auto parent = dyn_cast<LayoutAttr>(attr.getParent());
448 return parent.delinearizeId(builder, loc, linearId);
454FailureOr<SmallVector<SmallVector<Value>>>
455SliceAttr::computeDistributedCoords(OpBuilder &builder, Location loc,
456 Value linearId, ArrayRef<int64_t> shape) {
457 assert(getRank() ==
static_cast<int64_t
>(shape.size()) &&
"invalid shape.");
458 if (!isForWorkgroup())
461 SmallVector<int64_t> layout;
462 SmallVector<int64_t> subShape;
463 if (isForWorkgroup()) {
464 layout = getEffectiveSgLayoutAsInt();
465 subShape = getEffectiveSgDataAsInt();
466 }
else if (isForSubgroup()) {
467 layout = getEffectiveLaneLayoutAsInt();
468 subShape = getEffectiveLaneDataAsInt();
473 if (subShape.empty()) {
475 subShape = derivedShape.value();
481 auto maybeIds = delinearizeId(builder, loc, linearId);
487 ArrayRef<int64_t> dims = flatten().getDims().
asArrayRef();
488 SmallVector<Value> sgIds =
489 XeGPUDialect::slice(ArrayRef<Value>(*maybeIds), dims);
491 return genCoordinates(builder, loc, sgIds, layout, subShape, shape);
494bool SliceAttr::isSliceOf(
const xegpu::DistributeLayoutAttr &other) {
495 auto flattenedThis = flatten();
498 if (
auto otherLayout = dyn_cast<xegpu::LayoutAttr>(other))
499 return flattenedThis.getParent() == otherLayout;
501 auto flattenedOther = dyn_cast<xegpu::SliceAttr>(other).flatten();
503 if (flattenedThis.getParent() != flattenedOther.getParent())
507 llvm::SmallDenseSet<int64_t> thisDims(
508 flattenedThis.getDims().asArrayRef().begin(),
509 flattenedThis.getDims().asArrayRef().end());
510 return llvm::all_of(flattenedOther.getDims().asArrayRef(),
511 [&](int64_t dim) { return thisDims.contains(dim); });
519RangeAttr::verify(llvm::function_ref<mlir::InFlightDiagnostic()>
emitError,
520 IntegerAttr startOfRange, IntegerAttr endOfRange) {
521 if (startOfRange.getInt() >= endOfRange.getInt())
522 return emitError() <<
"'end' : " << endOfRange.getInt()
523 <<
" must be greater than 'start' : "
524 << startOfRange.getInt();
533mlir::Type TensorDescType::parse(AsmParser &parser) {
534 llvm::SmallVector<int64_t> shape;
535 mlir::Type elementType;
536 mlir::FailureOr<mlir::Attribute> encoding;
537 mlir::FailureOr<mlir::Attribute> layout;
545 parser.
emitError(shapeLoc,
"failed to parse parameter 'shape'");
550 if (mlir::failed(parser.
parseType(elementType))) {
551 parser.
emitError(elemTypeLoc,
"failed to parse parameter 'elementType'");
557 mlir::Attribute attr;
559 if (mlir::succeeded(res)) {
560 if (mlir::isa<LayoutAttr>(attr)) {
564 if (mlir::isa<BlockTensorDescAttr, ScatterTensorDescAttr>(attr)) {
577 return TensorDescType::getChecked(
579 elementType, encoding.value_or(BlockTensorDescAttr::get(ctxt)),
580 layout.value_or(mlir::Attribute()));
583void TensorDescType::print(AsmPrinter &printer)
const {
587 for (int64_t dim : shape) {
588 if (mlir::ShapedType::isDynamic(dim))
597 auto encoding = getEncoding();
598 auto blockAttr = llvm::dyn_cast_if_present<BlockTensorDescAttr>(encoding);
599 if (encoding && (!blockAttr || !blockAttr.hasDefaultsOnly()))
600 printer <<
", " << encoding;
602 if (
auto layout = getLayout())
603 printer <<
", " << layout;
608TensorDescType TensorDescType::get(llvm::ArrayRef<int64_t> shape,
609 mlir::Type elementType,
int array_length,
611 MemorySpace memory_space,
612 mlir::Attribute layout) {
614 auto attr = BlockTensorDescAttr::get(context, memory_space, array_length,
616 return Base::get(context, shape, elementType, attr, layout);
619TensorDescType TensorDescType::get(llvm::ArrayRef<int64_t> shape,
620 mlir::Type elementType,
int chunk_size,
621 MemorySpace memory_space,
622 mlir::Attribute layout) {
624 auto attr = ScatterTensorDescAttr::get(context, memory_space, chunk_size);
625 return Base::get(context, shape, elementType, attr, layout);
629TensorDescType::verify(llvm::function_ref<InFlightDiagnostic()>
emitError,
630 llvm::ArrayRef<int64_t> shape, mlir::Type elementType,
631 mlir::Attribute encoding, mlir::Attribute layout) {
632 size_t rank = shape.size();
635 return emitError() <<
"expected non-zero rank tensor";
637 auto blockAttr = mlir::dyn_cast_if_present<BlockTensorDescAttr>(encoding);
639 MemorySpaceAttr memorySpaceAttr = blockAttr.getMemorySpace();
640 if (rank > 1 && memorySpaceAttr &&
641 memorySpaceAttr.getValue() == MemorySpace::SLM)
642 return emitError() <<
"SLM is only supported for 1D block tensor";
647 int chunkAlignmentFactor =
651 auto scatterAttr = mlir::dyn_cast_if_present<ScatterTensorDescAttr>(encoding);
653 int64_t chunkSize = scatterAttr.getChunkSizeAsInt();
654 if (rank == 1 && chunkSize != 1)
655 return emitError() <<
"expected non-contiguous elements for 1D tensor";
661 if (shape.back() != chunkSize)
662 return emitError() <<
"expected last dim of tensor to match chunk size";
663 if (shape.back() % chunkAlignmentFactor != 0)
664 return emitError() <<
"expected last dim of tensor to be a multiple of "
665 << chunkAlignmentFactor;
669 auto layoutAttr = llvm::dyn_cast_if_present<LayoutAttr>(layout);
671 if (rank != (
size_t)layoutAttr.getRank())
672 return emitError() <<
"expected layout rank to match tensor rank";
674 auto laneData = layoutAttr.getLaneData();
675 if (scatterAttr && laneData) {
679 int64_t chunkSize = scatterAttr.getChunkSizeAsInt();
680 if (chunkSize > 1 && laneData[rank - 1] % chunkAlignmentFactor)
682 <<
"expected last dim of lane_data to be a multiple of: "
683 << chunkAlignmentFactor;
686 if (!XeGPUDialect::isEvenlyDistributable(shape, layoutAttr)) {
687 std::string shapeStr;
688 llvm::raw_string_ostream stream(shapeStr);
689 llvm::interleaveComma(shape, stream);
690 return emitError() <<
"cannot distribute [" << shapeStr <<
"] using "
700mlir::Type MemDescType::parse(AsmParser &parser) {
701 llvm::SmallVector<int64_t> shape;
702 mlir::Type elementType;
703 mlir::FailureOr<MemLayoutAttr> layout;
711 parser.
emitError(shapeLoc,
"failed to parse parameter 'shape'");
716 if (mlir::failed(parser.
parseType(elementType))) {
717 parser.
emitError(elemTypeLoc,
"failed to parse parameter 'elementType'");
725 if (mlir::failed(res))
735 return MemDescType::getChecked(
737 elementType, layout.value_or(MemLayoutAttr()));
740void MemDescType::print(AsmPrinter &printer)
const {
747 if (
auto layout = getMemLayout())
748 printer <<
", " << layout;
757Attribute MemLayoutAttr::parse(AsmParser &parser, Type type) {
762 llvm::SmallDenseSet<StringRef> seenKeys;
763 SmallVector<NamedAttribute> attributes;
765 auto parseElt = [&]() -> ParseResult {
768 return parser.
emitError(loc,
"expected valid attribute name");
770 if (!seenKeys.insert(nameId).second)
771 return parser.
emitError(loc,
"duplicate key '")
772 << nameId <<
" in mem layout attribute";
780 attributes.emplace_back(nameId, attr);
796 loc, context, DictionaryAttr::get(context, attributes));
799void MemLayoutAttr::print(AsmPrinter &printer)
const {
801 ArrayRef<NamedAttribute> attrs = getAttrs().getValue();
802 for (
size_t i = 0; i < attrs.size(); i++) {
803 printer << attrs[i].getName().str() <<
" = " << attrs[i].getValue();
804 if (i < attrs.size() - 1)
813template <
typename ArithOp>
818 return ArithOp::create(builder, loc, aVal, bVal).getResult();
823 genBinOp<arith::DivSIOp>(a, builder.getIndexAttr(b), loc, builder)
827 genBinOp<arith::RemSIOp>(a, builder.getIndexAttr(b), loc, builder)
831 genBinOp<arith::MulIOp>(a, builder.getIndexAttr(b), loc, builder)
834#define add(a, b) genBinOp<arith::AddIOp>(a, b, loc, builder)
843 assert(offsets.size() == blockShape.size() &&
844 "offsets and blockShape must have the same size");
848 for (
auto [offset, block] : llvm::zip(offsets, blockShape)) {
849 divs.push_back(
div(offset, block));
850 rems.push_back(
rem(offset, block));
852 blockedOffsets.append(divs.begin(), divs.end());
853 blockedOffsets.append(rems.begin(), rems.end());
855 return blockedOffsets;
865 for (
Attribute attr : strideAttr.getValue()) {
866 strides.push_back(cast<IntegerAttr>(attr).getInt());
874 llvm::to_vector<4>(llvm::seq<int>(0, strides.size()));
875 llvm::sort(perm, [&](
int a,
int b) {
return strides[a] < strides[
b]; });
877 assert(strides[perm[0]] == 1 &&
"inner most dim must have stride 1");
879 SmallVector<int64_t> innerBlkStride(innerBlkShape.size());
880 innerBlkStride[perm[0]] = 1;
881 for (
size_t i = 1; i < perm.size(); ++i)
882 innerBlkStride[perm[i]] =
883 innerBlkStride[perm[i - 1]] * innerBlkShape[perm[i - 1]];
889 SmallVector<int64_t> matrixShapeOrig(matrixShape.size());
890 SmallVector<int64_t> BlkShapeOrig(matrixShape.size());
891 for (
size_t i = 0; i < perm.size() - 1; ++i) {
892 matrixShapeOrig[perm[i]] = strides[perm[i + 1]] / strides[perm[i]];
893 BlkShapeOrig[perm[i]] = matrixShapeOrig[perm[i]] / innerBlkShape[perm[i]];
896 int64_t innerBlkSize = 1;
897 for (
auto s : innerBlkShape)
900 SmallVector<int64_t> outerBlkStride(matrixShape.size());
901 outerBlkStride[perm[0]] = innerBlkSize;
902 for (
size_t i = 0; i < perm.size() - 1; ++i) {
903 outerBlkStride[perm[i + 1]] =
904 outerBlkStride[perm[i]] * BlkShapeOrig[perm[i]];
908 SmallVector<int64_t> blockedStrides;
909 blockedStrides.append(outerBlkStride.begin(), outerBlkStride.end());
910 blockedStrides.append(innerBlkStride.begin(), innerBlkStride.end());
912 return blockedStrides;
916Value MemDescType::getLinearOffsets(OpBuilder &builder, Location loc,
917 ArrayRef<OpFoldResult> offsets) {
920 SmallVector<int64_t> blockShape = getBlockShape();
921 SmallVector<int64_t> strides = getStrideShape();
922 SmallVector<OpFoldResult> blockedOffsets;
925 if (llvm::equal(blockShape, matrixShape)) {
927 strides.erase(strides.begin(), strides.begin() + matrixShape.size());
929 assert(offsets.size() == blockShape.size() &&
930 "offsets and blockShape must have the same size");
934 SmallVector<OpFoldResult> divs, rems;
936 for (
auto [offset, block] : llvm::zip(offsets, blockShape)) {
937 divs.push_back(
div(offset, block));
938 rems.push_back(
rem(offset, block));
940 blockedOffsets.append(divs.begin(), divs.end());
941 blockedOffsets.append(rems.begin(), rems.end());
942 offsets = blockedOffsets;
947 for (
size_t i = 0; i < offsets.size(); ++i) {
948 OpFoldResult mulResult =
mul(offsets[i], strides[i]);
950 linearOffset = arith::AddIOp::create(builder, loc, mulVal, linearOffset);
959#include <mlir/Dialect/XeGPU/IR/XeGPUDialect.cpp.inc>
960#define GET_ATTRDEF_CLASSES
961#include <mlir/Dialect/XeGPU/IR/XeGPUAttrs.cpp.inc>
962#define GET_TYPEDEF_CLASSES
963#include <mlir/Dialect/XeGPU/IR/XeGPUTypes.cpp.inc>
static Type getElementType(Type type)
Determine the element type of type.
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
MLIRContext * getContext() const
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual ParseResult parseDimensionList(SmallVectorImpl< int64_t > &dimensions, bool allowDynamic=true, bool withTrailingX=true)=0
Parse a dimension list of a tensor or memref type.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
auto getChecked(SMLoc loc, ParamsT &&...params)
Invoke the getChecked method of the given Attribute or Type class, using the provided location to emi...
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseGreater()=0
Parse a '>' token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
void printDimensionList(ArrayRef< int64_t > shape)
Attributes are known-constant values of operations.
static BoolAttr get(MLIRContext *context, bool value)
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
This class helps build Operations.
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...
This class represents a single result from folding an operation.
A range-style iterator that allows for iterating over the offsets of all potential tiles of size tile...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Specialization of arith.constant op that returns an integer of index type.
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< int64_t > content)
ArrayRef< T > asArrayRef() const
auto getDims(VectorType vType)
Returns a range over the dims (size and scalability) of a VectorType.
constexpr unsigned generalPackedFormatBitSize
SmallVector< OpFoldResult > getBlockedOffsets(OpBuilder &builder, Location loc, ArrayRef< OpFoldResult > offsets, ArrayRef< int64_t > blockShape)
OpFoldResult genBinOp(OpFoldResult a, OpFoldResult b, Location loc, OpBuilder &builder)
static SmallVector< SmallVector< Value > > genCoordinates(OpBuilder &builder, Location loc, SmallVector< Value > delinearizedId, ArrayRef< int64_t > subShapesLayout, ArrayRef< int64_t > subShape, ArrayRef< int64_t > srcShape)
Include the generated interface declarations.
detail::DenseArrayAttrImpl< int64_t > DenseI64ArrayAttr
SmallVector< int64_t > computeElementwiseMul(ArrayRef< int64_t > v1, ArrayRef< int64_t > v2)
Return a vector containing llvm::zip_equal(v1, v2) multiplied elementwise.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
detail::DenseArrayAttrImpl< int32_t > DenseI32ArrayAttr
Value getValueOrCreateConstantIndexOp(OpBuilder &b, Location loc, OpFoldResult ofr)
Converts an OpFoldResult to a Value.
std::optional< SmallVector< int64_t > > computeShapeRatio(ArrayRef< int64_t > shape, ArrayRef< int64_t > subShape)
Return the multi-dimensional integral ratio of subShape to the trailing dimensions of shape.