29#include "llvm/ADT/ArrayRef.h"
30#include "llvm/ADT/TypeSwitch.h"
31#include "llvm/Support/ErrorHandling.h"
44 for (
size_t i = 0; i <
shape.size(); ++i) {
55template <
typename CallableT>
58 Type indexType = IndexType::get(ctx);
63 indexAsAttr.push_back(IntegerAttr::get(indexType, dim));
64 walker(ArrayAttr::get(ctx, indexAsAttr));
74 MemRefType memrefType) {
76 for (
auto [coord, dimSize] : llvm::zip(
indices, memrefType.getShape())) {
77 IntegerAttr coordAttr;
81 std::optional<uint64_t> coordInt = coordAttr.getValue().tryZExtValue();
82 if (!coordInt || coordInt.value() >=
static_cast<uint64_t
>(dimSize))
84 index.push_back(coordAttr);
86 return ArrayAttr::get(ctx,
index);
99 auto isVScale = [](
Value v) {
111 if (
auto mul = dyn_cast<arith::MulIOp>(defOp)) {
112 if (isVScale(
mul.getLhs()))
114 if (isVScale(
mul.getRhs()))
124 if (type.hasStaticShape()) {
125 std::optional<int64_t> numElements =
126 ShapedType::tryGetNumElements(type.getShape());
130 if (*numElements == 1)
131 return {
MemorySlot{getResult(), type.getElementType()}};
137 if (VectorType::isValidElementType(type.getElementType())) {
140 if (llvm::is_contained(type.getShape(), 0))
144 if (type.hasStaticShape())
145 return {
MemorySlot{getResult(), VectorType::get(type.getShape(),
146 type.getElementType())}};
150 if (type.getRank() == 1 && type.isDynamicDim(0)) {
151 if (std::optional<int64_t> multiple =
153 multiple && *multiple > 0)
155 VectorType::get({*multiple}, type.getElementType(),
165 return ub::PoisonOp::create(builder, getLoc(), slot.
valueType);
168std::optional<PromotableAllocationOpInterface>
169memref::AllocaOp::handlePromotionComplete(
const MemorySlot &slot,
172 if (defaultValue && defaultValue.
use_empty())
181void memref::AllocaOp::handleBlockArgument(
const MemorySlot &slot,
186memref::AllocaOp::getDestructurableSlots() {
187 MemRefType memrefType =
getType();
188 auto destructurable = llvm::dyn_cast<DestructurableTypeInterface>(memrefType);
192 std::optional<DenseMap<Attribute, Type>> destructuredType =
193 destructurable.getSubelementIndexMap();
194 if (!destructuredType)
209 auto memrefType = llvm::cast<DestructurableTypeInterface>(
getType());
210 for (
Attribute usedIndex : usedIndices) {
211 Type elemType = memrefType.getTypeAtIndex(usedIndex);
212 MemRefType elemPtr = MemRefType::get({}, elemType);
213 auto subAlloca = memref::AllocaOp::create(builder, getLoc(), elemPtr);
214 newAllocators.push_back(subAlloca);
216 {subAlloca.getResult(), elemType});
222std::optional<DestructurableAllocationOpInterface>
223memref::AllocaOp::handleDestructuringComplete(
225 assert(slot.
ptr == getResult());
233bool memref::LoadOp::loadsFrom(
const MemorySlot &slot) {
234 return getMemRef() == slot.
ptr;
237bool memref::LoadOp::storesTo(
const MemorySlot &slot) {
return false; }
242 llvm_unreachable(
"getStored should not be called on LoadOp");
245bool memref::LoadOp::canUsesBeRemoved(
249 if (blockingUses.size() != 1)
251 Value blockingUse = (*blockingUses.begin())->get();
252 return blockingUse == slot.
ptr && getMemRef() == slot.
ptr &&
262 getResult().replaceAllUsesWith(reachingDefinition);
273 if (slot.
ptr != getMemRef())
279 usedIndices.insert(
index);
290 setMemRef(memorySlot.
ptr);
291 getIndicesMutable().clear();
295bool memref::StoreOp::loadsFrom(
const MemorySlot &slot) {
return false; }
297bool memref::StoreOp::storesTo(
const MemorySlot &slot) {
298 return getMemRef() == slot.
ptr;
310bool memref::StoreOp::canUsesBeRemoved(
314 if (blockingUses.size() != 1)
316 Value blockingUse = (*blockingUses.begin())->get();
317 return blockingUse == slot.
ptr && getMemRef() == slot.
ptr &&
335 if (slot.
ptr != getMemRef() || getValue() == slot.
ptr)
341 usedIndices.insert(
index);
352 setMemRef(memorySlot.
ptr);
353 getIndicesMutable().clear();
362struct MemRefDestructurableTypeExternalModel
363 :
public DestructurableTypeInterface::ExternalModel<
364 MemRefDestructurableTypeExternalModel, MemRefType> {
365 std::optional<DenseMap<Attribute, Type>>
366 getSubelementIndexMap(Type type)
const {
367 auto memrefType = llvm::cast<MemRefType>(type);
368 constexpr int64_t maxMemrefSizeForDestructuring = 16;
369 if (!memrefType.hasStaticShape())
371 std::optional<int64_t> numElements =
372 ShapedType::tryGetNumElements(memrefType.getShape());
373 if (!numElements || *numElements > maxMemrefSizeForDestructuring ||
379 memrefType.getContext(), memrefType.getShape(), [&](Attribute index) {
380 destructured.insert({index, memrefType.getElementType()});
387 auto memrefType = llvm::cast<MemRefType>(type);
388 auto coordArrAttr = llvm::dyn_cast<ArrayAttr>(
index);
389 if (!coordArrAttr || coordArrAttr.size() != memrefType.getShape().size())
392 Type indexType = IndexType::get(memrefType.getContext());
393 for (
const auto &[coordAttr, dimSize] :
394 llvm::zip(coordArrAttr, memrefType.getShape())) {
395 auto coord = llvm::dyn_cast<IntegerAttr>(coordAttr);
396 if (!coord || coord.getType() != indexType || coord.getInt() < 0 ||
397 coord.getInt() >= dimSize)
401 return memrefType.getElementType();
412 MemRefType::attachInterface<MemRefDestructurableTypeExternalModel>(*ctx);
static Type getTypeAtIndex(const DestructurableMemorySlot &slot, Attribute index)
Returns the subslot's type at the requested index.
static Attribute getAttributeIndexFromIndexOperands(MLIRContext *ctx, ValueRange indices, MemRefType memrefType)
Returns the index of a memref in attribute form, given its indices.
static std::optional< int64_t > matchVScaleMultiple(Value size)
Returns the scalable vector width a vscale-sized memref maps to: the factor C when size is a known mu...
static LogicalResult nextIndex(ArrayRef< int64_t > shape, MutableArrayRef< int64_t > index)
Walks over the indices of the elements of a tensor of a given shape by updating index in place to the...
static void walkIndicesAsAttr(MLIRContext *ctx, ArrayRef< int64_t > shape, CallableT &&walker)
Calls walker for each index within a tensor of a given shape, providing the index as an array attribu...
static void getDynamicSizes(RankedTensorType tp, ValueRange sizes, SmallVectorImpl< Value > &dynSizes)
Collects the dynamic dimension sizes for tp with the assumption that sizes are the dimension sizes fo...
Attributes are known-constant values of operations.
This class represents an argument of a Block.
The main mechanism for performing data layout queries.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
MLIRContext is the top-level object for a collection of MLIR operations.
This class helps build Operations.
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
Operation is the basic unit of execution within MLIR.
OperationName getName()
The name of an operation is the key identifier for it.
void erase()
Remove this operation from its parent block and delete it.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
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...
bool use_empty() const
Returns true if this value has no uses.
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.
void registerDestructurableTypeExternalModels(DialectRegistry ®istry)
Operation::operand_range getIndices(Operation *op)
Get the indices that the given load/store operation is operating on.
MemRefType getMemRefType(T &&t)
Convenience method to abbreviate casting getType().
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
DeletionKind
Returned by operation promotion logic requesting the deletion of an operation.
@ Keep
Keep the operation after promotion.
@ Delete
Delete the operation after promotion.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
Memory slot attached with information about its destructuring procedure.
DenseMap< Attribute, Type > subelementTypes
Maps an index within the memory slot to the corresponding subelement type.
Represents a slot in memory.
Type valueType
Type of the value contained in the slot.
Value ptr
Pointer to the memory slot, used by operations to refer to it.