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.elemType));
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.elemType;
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.elemType == 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.elemType, 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.elemType);
171}
172
173//===----------------------------------------------------------------------===//
174// Interfaces for CastOp
175//===----------------------------------------------------------------------===//
176
177bool cir::CastOp::canUsesBeRemoved(
178 const SmallPtrSetImpl<OpOperand *> &blockingUses,
179 SmallVectorImpl<OpOperand *> &newBlockingUses,
180 const DataLayout &dataLayout) {
181 if (getKind() == cir::CastKind::bitcast)
182 return forwardToUsers(*this, newBlockingUses);
183 return false;
184}
185
186DeletionKind cir::CastOp::removeBlockingUses(
187 const SmallPtrSetImpl<OpOperand *> &blockingUses, OpBuilder &builder) {
188 return DeletionKind::Delete;
189}
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.