24#include "llvm/ADT/ArrayRef.h"
25#include "llvm/ADT/TypeSwitch.h"
26#include "llvm/Support/ErrorHandling.h"
39 for (
size_t i = 0; i <
shape.size(); ++i) {
50template <
typename CallableT>
53 Type indexType = IndexType::get(ctx);
58 indexAsAttr.push_back(IntegerAttr::get(indexType, dim));
59 walker(ArrayAttr::get(ctx, indexAsAttr));
74 auto isVScale = [](
Value v) {
86 if (
auto mul = dyn_cast<arith::MulIOp>(defOp)) {
87 if (isVScale(
mul.getLhs()))
89 if (isVScale(
mul.getRhs()))
99 if (type.hasStaticShape()) {
100 std::optional<int64_t> numElements =
101 ShapedType::tryGetNumElements(type.getShape());
105 if (*numElements == 1)
106 return {
MemorySlot{getResult(), type.getElementType()}};
112 if (VectorType::isValidElementType(type.getElementType())) {
115 if (llvm::is_contained(type.getShape(), 0))
119 if (type.hasStaticShape())
120 return {
MemorySlot{getResult(), VectorType::get(type.getShape(),
121 type.getElementType())}};
125 if (type.getRank() == 1 && type.isDynamicDim(0)) {
126 if (std::optional<int64_t> multiple =
128 multiple && *multiple > 0)
130 VectorType::get({*multiple}, type.getElementType(),
140 return ub::PoisonOp::create(builder, getLoc(), slot.
elemType);
143std::optional<PromotableAllocationOpInterface>
144memref::AllocaOp::handlePromotionComplete(
const MemorySlot &slot,
147 if (defaultValue && defaultValue.
use_empty())
153void memref::AllocaOp::handleBlockArgument(
const MemorySlot &slot,
158memref::AllocaOp::getDestructurableSlots() {
159 MemRefType memrefType =
getType();
160 auto destructurable = llvm::dyn_cast<DestructurableTypeInterface>(memrefType);
164 std::optional<DenseMap<Attribute, Type>> destructuredType =
165 destructurable.getSubelementIndexMap();
166 if (!destructuredType)
181 auto memrefType = llvm::cast<DestructurableTypeInterface>(
getType());
182 for (
Attribute usedIndex : usedIndices) {
183 Type elemType = memrefType.getTypeAtIndex(usedIndex);
184 MemRefType elemPtr = MemRefType::get({}, elemType);
185 auto subAlloca = memref::AllocaOp::create(builder, getLoc(), elemPtr);
186 newAllocators.push_back(subAlloca);
188 {subAlloca.getResult(), elemType});
194std::optional<DestructurableAllocationOpInterface>
195memref::AllocaOp::handleDestructuringComplete(
197 assert(slot.
ptr == getResult());
206bool memref::LoadOp::loadsFrom(
const MemorySlot &slot) {
210bool memref::LoadOp::storesTo(
const MemorySlot &slot) {
return false; }
215 llvm_unreachable(
"getStored should not be called on LoadOp");
218bool memref::LoadOp::canUsesBeRemoved(
222 if (blockingUses.size() != 1)
224 Value blockingUse = (*blockingUses.begin())->get();
235 getResult().replaceAllUsesWith(reachingDefinition);
245 MemRefType memrefType) {
247 for (
auto [coord, dimSize] : llvm::zip(
indices, memrefType.getShape())) {
248 IntegerAttr coordAttr;
252 std::optional<uint64_t> coordInt = coordAttr.getValue().tryZExtValue();
253 if (!coordInt || coordInt.value() >=
static_cast<uint64_t
>(dimSize))
255 index.push_back(coordAttr);
257 return ArrayAttr::get(ctx,
index);
270 usedIndices.insert(
index);
281 setMemRef(memorySlot.
ptr);
282 getIndicesMutable().clear();
286bool memref::StoreOp::loadsFrom(
const MemorySlot &slot) {
return false; }
288bool memref::StoreOp::storesTo(
const MemorySlot &slot) {
298bool memref::StoreOp::canUsesBeRemoved(
302 if (blockingUses.size() != 1)
304 Value blockingUse = (*blockingUses.begin())->get();
326 usedIndices.insert(
index);
337 setMemRef(memorySlot.
ptr);
338 getIndicesMutable().clear();
348struct MemRefDestructurableTypeExternalModel
349 :
public DestructurableTypeInterface::ExternalModel<
350 MemRefDestructurableTypeExternalModel, MemRefType> {
351 std::optional<DenseMap<Attribute, Type>>
352 getSubelementIndexMap(Type type)
const {
353 auto memrefType = llvm::cast<MemRefType>(type);
354 constexpr int64_t maxMemrefSizeForDestructuring = 16;
355 if (!memrefType.hasStaticShape())
357 std::optional<int64_t> numElements =
358 ShapedType::tryGetNumElements(memrefType.getShape());
359 if (!numElements || *numElements > maxMemrefSizeForDestructuring ||
365 memrefType.getContext(), memrefType.getShape(), [&](Attribute index) {
366 destructured.insert({index, memrefType.getElementType()});
373 auto memrefType = llvm::cast<MemRefType>(type);
374 auto coordArrAttr = llvm::dyn_cast<ArrayAttr>(
index);
375 if (!coordArrAttr || coordArrAttr.size() != memrefType.getShape().size())
378 Type indexType = IndexType::get(memrefType.getContext());
379 for (
const auto &[coordAttr, dimSize] :
380 llvm::zip(coordArrAttr, memrefType.getShape())) {
381 auto coord = llvm::dyn_cast<IntegerAttr>(coordAttr);
382 if (!coord || coord.getType() != indexType || coord.getInt() < 0 ||
383 coord.getInt() >= dimSize)
387 return memrefType.getElementType();
399 MemRefType::attachInterface<MemRefDestructurableTypeExternalModel>(*ctx);
static Value getMemRef(Operation *memOp)
Returns the memref being read/written by a memref/affine load/store op.
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 registerMemorySlotExternalModels(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.
Value ptr
Pointer to the memory slot, used by operations to refer to it.
Type elemType
Type of the value contained in the slot.