MLIR 24.0.0git
MemorySlotInterfacesImpl.cpp
Go to the documentation of this file.
1//===- MemorySlotInterfacesImpl.cpp - Mem2Reg for Vector ops --------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements memory slot interface models for
10// `vector.transfer_read` and `vector.transfer_write`. These models implement
11// `PromotableMemOpInterface` so Mem2Reg can replace vector transfers with uses
12// and definitions of a vector SSA value. The models for `memref.subview`
13// live in the MemRef dialect.
14//
15// A read uses the slot's current value; a write defines its next value.
16// Static subviews use a vector matching the subview's shape: reads extract that
17// sub-vector from the parent, and writes insert it back into the parent.
18// Supported transfers through dynamic subviews use a vector type matching the
19// whole static parent, and the subview's slot holds that whole vector. Reads
20// pad lanes outside the runtime extent, and writes preserve the previous value
21// of those lanes. `arith.select` implements this behavior and also handles
22// lanes disabled by a transfer's mask operand.
23//
24// Transfers wrapped in `vector.mask` prevent promotion because that op does
25// not implement `PromotableRegionOpInterface`, which Mem2Reg requires to
26// promote accesses inside a region.
27//
28//===----------------------------------------------------------------------===//
29
31
39
40using namespace mlir;
41using namespace mlir::vector;
42
43//===----------------------------------------------------------------------===//
44// Utilities
45//===----------------------------------------------------------------------===//
46
47/// Returns whether `xferOp` can be promoted to use or define `slot`'s vector
48/// value. The transfer's memref base must be the slot pointer, its vector type
49/// must equal `slot.valueType`, its indices must be zero, and its permutation
50/// map must be the identity. Out-of-bounds dimensions are allowed only for a
51/// supported dynamic subview.
52///
53/// More general transfers may be supportable, but their value depends on
54/// motivating use cases, implementation complexity, and generated code quality.
55static bool
56isPromotableTransfer(VectorTransferOpInterface xferOp, const MemorySlot &slot,
57 const SmallPtrSetImpl<OpOperand *> &blockingUses) {
58 // The transfer's memref base must be the slot pointer.
59 if (blockingUses.size() != 1)
60 return false;
61 Value blockingUse = (*blockingUses.begin())->get();
62 if (blockingUse != slot.ptr || xferOp.getBase() != slot.ptr)
63 return false;
64
65 // Reject the tensor form (already implied, since slot pointers are memrefs).
66 if (!isa<MemRefType>(xferOp.getBase().getType()))
67 return false;
68
69 // Exact type match pins rank/extents/element type/scalable dims.
70 if (xferOp.getVectorType() != slot.valueType)
71 return false;
72
73 // Access must start at the buffer origin in every dimension.
74 for (Value index : xferOp.getIndices()) {
75 std::optional<int64_t> constIndex = getConstantIntValue(index);
76 if (!constIndex || *constIndex != 0)
77 return false;
78 }
79
80 // Identity map: no broadcast or transpose.
81 if (!xferOp.getPermutationMap().isIdentity())
82 return false;
83
84 // Out-of-bounds is allowed only for a dynamic view.
85 if (xferOp.hasOutOfBoundsDim() && !memref::isDynamicSubViewSlot(slot.ptr))
86 return false;
87
88 return true;
89}
90
91//===----------------------------------------------------------------------===//
92// PromotableMemOpInterface models
93//===----------------------------------------------------------------------===//
94
95namespace {
96/// `PromotableMemOpInterface` model for `vector.transfer_read`.
97struct TransferReadOpMemOpModel
98 : public PromotableMemOpInterface::ExternalModel<TransferReadOpMemOpModel,
99 vector::TransferReadOp> {
100 bool loadsFrom(Operation *op, const MemorySlot &slot) const {
101 return cast<vector::TransferReadOp>(op).getBase() == slot.ptr;
102 }
103
104 bool storesTo(Operation *op, const MemorySlot &slot) const { return false; }
105
106 Value getStored(Operation *op, const MemorySlot &slot, OpBuilder &builder,
107 Value reachingDef, const DataLayout &dataLayout) const {
108 llvm_unreachable("getStored should not be called on TransferReadOp");
109 }
110
111 bool canUsesBeRemoved(Operation *op, const MemorySlot &slot,
112 const SmallPtrSetImpl<OpOperand *> &blockingUses,
113 SmallVectorImpl<OpOperand *> &newBlockingUses,
114 const DataLayout &dataLayout) const {
115 return isPromotableTransfer(cast<VectorTransferOpInterface>(op), slot,
116 blockingUses);
117 }
118
119 // Replace the read with the reaching definition, selecting padding for lanes
120 // outside the subview's extent or disabled by the transfer's mask.
121 // PromotableAliaserInterface::projectSlotValueToAliasValue supplies the whole
122 // parent vector for a dynamic subview. Apply the extent mask here because
123 // this hook has access to the transfer's padding operand. If the transfer
124 // also has a mask operand, combine the two masks with arith.andi.
126 removeBlockingUses(Operation *op, const MemorySlot &slot,
127 const SmallPtrSetImpl<OpOperand *> &blockingUses,
128 OpBuilder &builder, Value reachingDefinition,
129 const DataLayout &dataLayout) const {
130 auto readOp = cast<vector::TransferReadOp>(op);
131 Location loc = op->getLoc();
132 Value mask = memref::buildDynamicSubViewMask(builder, loc, slot.ptr);
133 if (Value opMask = readOp.getMask())
134 mask = mask
135 ? arith::AndIOp::create(builder, loc, mask, opMask).getResult()
136 : opMask;
137
138 Value result = reachingDefinition;
139 if (mask) {
140 Value padSplat = vector::BroadcastOp::create(
141 builder, loc, readOp.getVectorType(), readOp.getPadding());
142 result = arith::SelectOp::create(builder, loc, mask, reachingDefinition,
143 padSplat);
144 }
145 readOp.getVector().replaceAllUsesWith(result);
146 return DeletionKind::Delete;
147 }
148};
149
150/// `PromotableMemOpInterface` model for `vector.transfer_write`.
151struct TransferWriteOpMemOpModel
152 : public PromotableMemOpInterface::ExternalModel<TransferWriteOpMemOpModel,
153 vector::TransferWriteOp> {
154 bool loadsFrom(Operation *op, const MemorySlot &slot) const { return false; }
155
156 bool storesTo(Operation *op, const MemorySlot &slot) const {
157 return cast<vector::TransferWriteOp>(op).getBase() == slot.ptr;
158 }
159
160 // The stored value is the transfer's vector, with inactive lanes preserved
161 // from the reaching definition when the transfer has a mask.
162 Value getStored(Operation *op, const MemorySlot &slot, OpBuilder &builder,
163 Value reachingDef, const DataLayout &dataLayout) const {
164 auto writeOp = cast<vector::TransferWriteOp>(op);
165 Value stored = writeOp.getValueToStore();
166 // PromotableAliaserInterface::projectAliasValueToSlotValue separately
167 // preserves parent lanes outside a dynamic subview's extent.
168 if (Value mask = writeOp.getMask())
169 stored = arith::SelectOp::create(builder, op->getLoc(), mask, stored,
170 reachingDef);
171 return stored;
172 }
173
174 bool canUsesBeRemoved(Operation *op, const MemorySlot &slot,
175 const SmallPtrSetImpl<OpOperand *> &blockingUses,
176 SmallVectorImpl<OpOperand *> &newBlockingUses,
177 const DataLayout &dataLayout) const {
178 return isPromotableTransfer(cast<VectorTransferOpInterface>(op), slot,
179 blockingUses);
180 }
181
182 // `getStored` already provided the value for later uses, so the write can
183 // simply be erased.
185 removeBlockingUses(Operation *op, const MemorySlot &slot,
186 const SmallPtrSetImpl<OpOperand *> &blockingUses,
187 OpBuilder &builder, Value reachingDefinition,
188 const DataLayout &dataLayout) const {
189 return DeletionKind::Delete;
190 }
191};
192} // namespace
193
194//===----------------------------------------------------------------------===//
195// Register external models
196//===----------------------------------------------------------------------===//
197
199 registry.addExtension(+[](MLIRContext *ctx, vector::VectorDialect *dialect) {
200 TransferReadOp::attachInterface<TransferReadOpMemOpModel>(*ctx);
201 TransferWriteOp::attachInterface<TransferWriteOpMemOpModel>(*ctx);
202 });
203}
static bool isPromotableTransfer(VectorTransferOpInterface xferOp, const MemorySlot &slot, const SmallPtrSetImpl< OpOperand * > &blockingUses)
Returns whether xferOp can be promoted to use or define slot's vector value.
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.
Definition MLIRContext.h:64
Location getLoc()
The source location the operation was defined or derived from.
Definition Operation.h:240
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
void replaceAllUsesWith(Value newValue)
Replace all uses of 'this' value with the new value, updating anything in the IR that uses 'this' to ...
Definition Value.h:149
Value buildDynamicSubViewMask(OpBuilder &builder, Location loc, Value slotPtr)
Builds a mask for the subview's valid region in the parent vector, or returns null if isDynamicSubVie...
bool isDynamicSubViewSlot(Value slotPtr)
Returns whether slotPtr is a dynamic memref.subview that can be promoted as an alias of the whole par...
void registerMemorySlotExternalModels(DialectRegistry &registry)
Include the generated interface declarations.
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
DeletionKind
Returned by operation promotion logic requesting the deletion of an operation.
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.