clang 24.0.0git
CIRMemorySlot.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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 MemorySlot-related interfaces for CIR dialect
10// operations.
11//
12//===----------------------------------------------------------------------===//
13
15
16using namespace mlir;
17
18/// Conditions the deletion of the operation to the removal of all its uses.
19static bool forwardToUsers(Operation *op,
20 SmallVectorImpl<OpOperand *> &newBlockingUses) {
21 for (Value result : op->getResults())
22 for (OpOperand &use : result.getUses())
23 newBlockingUses.push_back(&use);
24 return true;
25}
26
27//===----------------------------------------------------------------------===//
28// Interfaces for AllocaOp
29//===----------------------------------------------------------------------===//
30
31llvm::SmallVector<MemorySlot> cir::AllocaOp::getPromotableSlots() {
32 return {MemorySlot{getResult(), getAllocaType()}};
33}
34
35Value cir::AllocaOp::getDefaultValue(const MemorySlot &slot,
36 OpBuilder &builder) {
37 return cir::ConstantOp::create(builder, getLoc(),
38 cir::UndefAttr::get(slot.valueType));
39}
40
41void cir::AllocaOp::handleBlockArgument(const MemorySlot &slot,
42 BlockArgument argument,
43 OpBuilder &builder) {}
44
45std::optional<PromotableAllocationOpInterface>
46cir::AllocaOp::handlePromotionComplete(const MemorySlot &slot,
47 Value defaultValue, OpBuilder &builder) {
48 if (defaultValue && defaultValue.use_empty())
49 defaultValue.getDefiningOp()->erase();
50 this->erase();
51 return std::nullopt;
52}
53
54//===----------------------------------------------------------------------===//
55// Interfaces for LoadOp
56//===----------------------------------------------------------------------===//
57
58bool cir::LoadOp::loadsFrom(const MemorySlot &slot) {
59 return getAddr() == slot.ptr;
60}
61
62bool cir::LoadOp::storesTo(const MemorySlot &slot) { return false; }
63
64Value cir::LoadOp::getStored(const MemorySlot &slot, OpBuilder &builder,
65 Value reachingDef, const DataLayout &dataLayout) {
66 llvm_unreachable("getStored should not be called on LoadOp");
67}
68
69bool cir::LoadOp::canUsesBeRemoved(
70 const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
71 SmallVectorImpl<OpOperand *> &newBlockingUses,
72 const DataLayout &dataLayout) {
73 if (blockingUses.size() != 1)
74 return false;
75
76 // Volatile load or atomic load should not be removed.
77 if (getIsVolatile() || getMemOrder().has_value())
78 return false;
79
80 Value blockingUse = (*blockingUses.begin())->get();
81 return blockingUse == slot.ptr && getAddr() == slot.ptr &&
82 getType() == slot.valueType;
83}
84
85DeletionKind cir::LoadOp::removeBlockingUses(
86 const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
87 OpBuilder &builder, Value reachingDefinition,
88 const DataLayout &dataLayout) {
89 getResult().replaceAllUsesWith(reachingDefinition);
90 return DeletionKind::Delete;
91}
92
93//===----------------------------------------------------------------------===//
94// Interfaces for StoreOp
95//===----------------------------------------------------------------------===//
96
97bool cir::StoreOp::loadsFrom(const MemorySlot &slot) { return false; }
98
99bool cir::StoreOp::storesTo(const MemorySlot &slot) {
100 return getAddr() == slot.ptr;
101}
102
103Value cir::StoreOp::getStored(const MemorySlot &slot, OpBuilder &builder,
104 Value reachingDef, const DataLayout &dataLayout) {
105 return getValue();
106}
107
108bool cir::StoreOp::canUsesBeRemoved(
109 const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
110 SmallVectorImpl<OpOperand *> &newBlockingUses,
111 const DataLayout &dataLayout) {
112 if (blockingUses.size() != 1)
113 return false;
114
115 // Volatile store or atomic store should not be removed.
116 if (getIsVolatile() || getMemOrder().has_value())
117 return false;
118
119 Value blockingUse = (*blockingUses.begin())->get();
120 return blockingUse == slot.ptr && getAddr() == slot.ptr &&
121 getValue() != slot.ptr && slot.valueType == getValue().getType();
122}
123
124DeletionKind cir::StoreOp::removeBlockingUses(
125 const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
126 OpBuilder &builder, Value reachingDefinition,
127 const DataLayout &dataLayout) {
128 return DeletionKind::Delete;
129}
130
131//===----------------------------------------------------------------------===//
132// Interfaces for CopyOp
133//===----------------------------------------------------------------------===//
134
135bool cir::CopyOp::loadsFrom(const MemorySlot &slot) {
136 return getSrc() == slot.ptr;
137}
138
139bool cir::CopyOp::storesTo(const MemorySlot &slot) {
140 return getDst() == slot.ptr;
141}
142
143Value cir::CopyOp::getStored(const MemorySlot &slot, OpBuilder &builder,
144 Value reachingDef, const DataLayout &dataLayout) {
145 return cir::LoadOp::create(builder, getLoc(), slot.valueType, getSrc());
146}
147
148DeletionKind cir::CopyOp::removeBlockingUses(
149 const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
150 OpBuilder &builder, mlir::Value reachingDefinition,
151 const DataLayout &dataLayout) {
152 if (loadsFrom(slot))
153 cir::StoreOp::create(builder, getLoc(), reachingDefinition, getDst(),
154 /*is_volatile=*/false,
155 /*is_nontemporal=*/false,
156 /*alignment=*/mlir::IntegerAttr{},
157 /*sync_scope=*/cir::SyncScopeKindAttr(),
158 /*mem-order=*/cir::MemOrderAttr());
159 return DeletionKind::Delete;
160}
161
162bool cir::CopyOp::canUsesBeRemoved(
163 const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
164 SmallVectorImpl<OpOperand *> &newBlockingUses,
165 const DataLayout &dataLayout) {
166 if (getDst() == getSrc())
167 return false;
168
169 return getCopySizeInBytes(dataLayout) ==
170 dataLayout.getTypeSize(slot.valueType);
171}
172
173//===----------------------------------------------------------------------===//
174// Interfaces for MatrixColumnMajorLoadOp
175//===----------------------------------------------------------------------===//
176
177bool cir::MatrixColumnMajorLoadOp::loadsFrom(const MemorySlot &slot) {
178 return getValue() == slot.ptr;
179}
180
181bool cir::MatrixColumnMajorLoadOp::storesTo(const MemorySlot &slot) {
182 return false;
183}
184
185Value cir::MatrixColumnMajorLoadOp::getStored(const MemorySlot &slot,
186 OpBuilder &builder,
187 Value reachingDef,
188 const DataLayout &dataLayout) {
189 llvm_unreachable("getStored should not be called on MatrixColumnMajorLoadOp");
190}
191
192bool cir::MatrixColumnMajorLoadOp::canUsesBeRemoved(
193 const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
194 SmallVectorImpl<OpOperand *> &newBlockingUses,
195 const DataLayout &dataLayout) {
196 if (blockingUses.size() != 1)
197 return false;
198
199 // Volatile load should not be removed.
200 if (getIsVolatile())
201 return false;
202
203 Value blockingUse = (*blockingUses.begin())->get();
204 return blockingUse == slot.ptr && getValue() == slot.ptr &&
205 getType() == slot.valueType;
206}
207
208DeletionKind cir::MatrixColumnMajorLoadOp::removeBlockingUses(
209 const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
210 OpBuilder &builder, Value reachingDefinition,
211 const DataLayout &dataLayout) {
212 getResult().replaceAllUsesWith(reachingDefinition);
213 return DeletionKind::Delete;
214}
215
216//===----------------------------------------------------------------------===//
217// Interfaces for MatrixColumnMajorStoreOp
218//===----------------------------------------------------------------------===//
219
220bool cir::MatrixColumnMajorStoreOp::loadsFrom(const MemorySlot &slot) {
221 return false;
222}
223
224bool cir::MatrixColumnMajorStoreOp::storesTo(const MemorySlot &slot) {
225 return getValue() == slot.ptr;
226}
227
228Value cir::MatrixColumnMajorStoreOp::getStored(const MemorySlot &slot,
229 OpBuilder &builder,
230 Value reachingDef,
231 const DataLayout &dataLayout) {
232 return getMatrix();
233}
234
235bool cir::MatrixColumnMajorStoreOp::canUsesBeRemoved(
236 const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
237 SmallVectorImpl<OpOperand *> &newBlockingUses,
238 const DataLayout &dataLayout) {
239 if (blockingUses.size() != 1)
240 return false;
241
242 // Volatile store should not be removed.
243 if (getIsVolatile())
244 return false;
245
246 Value blockingUse = (*blockingUses.begin())->get();
247 return blockingUse == slot.ptr && getValue() == slot.ptr &&
248 getValue() != slot.ptr && slot.valueType == getValue().getType();
249}
250
251DeletionKind cir::MatrixColumnMajorStoreOp::removeBlockingUses(
252 const MemorySlot &slot, const SmallPtrSetImpl<OpOperand *> &blockingUses,
253 OpBuilder &builder, Value reachingDefinition,
254 const DataLayout &dataLayout) {
255 return DeletionKind::Delete;
256}
257
258//===----------------------------------------------------------------------===//
259// Interfaces for CastOp
260//===----------------------------------------------------------------------===//
261
262bool cir::CastOp::canUsesBeRemoved(
263 const SmallPtrSetImpl<OpOperand *> &blockingUses,
264 SmallVectorImpl<OpOperand *> &newBlockingUses,
265 const DataLayout &dataLayout) {
266 if (getKind() == cir::CastKind::bitcast)
267 return forwardToUsers(*this, newBlockingUses);
268 return false;
269}
270
271DeletionKind cir::CastOp::removeBlockingUses(
272 const SmallPtrSetImpl<OpOperand *> &blockingUses, OpBuilder &builder) {
273 return DeletionKind::Delete;
274}
static bool forwardToUsers(Operation *op, SmallVectorImpl< OpOperand * > &newBlockingUses)
Conditions the deletion of the operation to the removal of all its uses.
static Decl::Kind getKind(const Decl *D)
TokenType getType() const
Returns the token's type, e.g.