1 //===- OperationSupport.cpp -----------------------------------------------===//
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 contains out-of-line implementations of the support types that
10 // Operation and related classes build on top of.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "mlir/IR/OperationSupport.h"
15 #include "mlir/IR/Block.h"
16 #include "mlir/IR/Operation.h"
17 using namespace mlir;
18 
19 //===----------------------------------------------------------------------===//
20 // OperationState
21 //===----------------------------------------------------------------------===//
22 
23 OperationState::OperationState(Location location, StringRef name)
24     : location(location), name(name, location->getContext()) {}
25 
26 OperationState::OperationState(Location location, OperationName name)
27     : location(location), name(name) {}
28 
29 OperationState::OperationState(Location location, StringRef name,
30                                ValueRange operands, ArrayRef<Type> types,
31                                ArrayRef<NamedAttribute> attributes,
32                                ArrayRef<Block *> successors,
33                                MutableArrayRef<std::unique_ptr<Region>> regions)
34     : location(location), name(name, location->getContext()),
35       operands(operands.begin(), operands.end()),
36       types(types.begin(), types.end()),
37       attributes(attributes.begin(), attributes.end()),
38       successors(successors.begin(), successors.end()) {
39   for (std::unique_ptr<Region> &r : regions)
40     this->regions.push_back(std::move(r));
41 }
42 
43 void OperationState::addOperands(ValueRange newOperands) {
44   operands.append(newOperands.begin(), newOperands.end());
45 }
46 
47 void OperationState::addSuccessors(SuccessorRange newSuccessors) {
48   successors.append(newSuccessors.begin(), newSuccessors.end());
49 }
50 
51 Region *OperationState::addRegion() {
52   regions.emplace_back(new Region);
53   return regions.back().get();
54 }
55 
56 void OperationState::addRegion(std::unique_ptr<Region> &&region) {
57   regions.push_back(std::move(region));
58 }
59 
60 //===----------------------------------------------------------------------===//
61 // OperandStorage
62 //===----------------------------------------------------------------------===//
63 
64 detail::OperandStorage::OperandStorage(Operation *owner, ValueRange values)
65     : representation(0) {
66   auto &inlineStorage = getInlineStorage();
67   inlineStorage.numOperands = inlineStorage.capacity = values.size();
68   auto *operandPtrBegin = getTrailingObjects<OpOperand>();
69   for (unsigned i = 0, e = inlineStorage.numOperands; i < e; ++i)
70     new (&operandPtrBegin[i]) OpOperand(owner, values[i]);
71 }
72 
73 detail::OperandStorage::~OperandStorage() {
74   // Destruct the current storage container.
75   if (isDynamicStorage()) {
76     TrailingOperandStorage &storage = getDynamicStorage();
77     storage.~TrailingOperandStorage();
78     free(&storage);
79   } else {
80     getInlineStorage().~TrailingOperandStorage();
81   }
82 }
83 
84 /// Replace the operands contained in the storage with the ones provided in
85 /// 'values'.
86 void detail::OperandStorage::setOperands(Operation *owner, ValueRange values) {
87   MutableArrayRef<OpOperand> storageOperands = resize(owner, values.size());
88   for (unsigned i = 0, e = values.size(); i != e; ++i)
89     storageOperands[i].set(values[i]);
90 }
91 
92 /// Resize the storage to the given size. Returns the array containing the new
93 /// operands.
94 MutableArrayRef<OpOperand> detail::OperandStorage::resize(Operation *owner,
95                                                           unsigned newSize) {
96   TrailingOperandStorage &storage = getStorage();
97 
98   // If the number of operands is less than or equal to the current amount, we
99   // can just update in place.
100   unsigned &numOperands = storage.numOperands;
101   MutableArrayRef<OpOperand> operands = storage.getOperands();
102   if (newSize <= numOperands) {
103     // If the number of new size is less than the current, remove any extra
104     // operands.
105     for (unsigned i = newSize; i != numOperands; ++i)
106       operands[i].~OpOperand();
107     numOperands = newSize;
108     return operands.take_front(newSize);
109   }
110 
111   // If the new size is within the original inline capacity, grow inplace.
112   if (newSize <= storage.capacity) {
113     OpOperand *opBegin = operands.data();
114     for (unsigned e = newSize; numOperands != e; ++numOperands)
115       new (&opBegin[numOperands]) OpOperand(owner);
116     return MutableArrayRef<OpOperand>(opBegin, newSize);
117   }
118 
119   // Otherwise, we need to allocate a new storage.
120   unsigned newCapacity =
121       std::max(unsigned(llvm::NextPowerOf2(storage.capacity + 2)), newSize);
122   auto *newStorageMem =
123       malloc(TrailingOperandStorage::totalSizeToAlloc<OpOperand>(newCapacity));
124   auto *newStorage = ::new (newStorageMem) TrailingOperandStorage();
125   newStorage->numOperands = newSize;
126   newStorage->capacity = newCapacity;
127 
128   // Move the current operands to the new storage.
129   MutableArrayRef<OpOperand> newOperands = newStorage->getOperands();
130   std::uninitialized_copy(std::make_move_iterator(operands.begin()),
131                           std::make_move_iterator(operands.end()),
132                           newOperands.begin());
133 
134   // Destroy the original operands.
135   for (auto &operand : operands)
136     operand.~OpOperand();
137 
138   // Initialize any new operands.
139   for (unsigned e = newSize; numOperands != e; ++numOperands)
140     new (&newOperands[numOperands]) OpOperand(owner);
141 
142   // If the current storage is also dynamic, free it.
143   if (isDynamicStorage())
144     free(&storage);
145 
146   // Update the storage representation to use the new dynamic storage.
147   representation = reinterpret_cast<intptr_t>(newStorage);
148   representation |= DynamicStorageBit;
149   return newOperands;
150 }
151 
152 /// Erase an operand held by the storage.
153 void detail::OperandStorage::eraseOperand(unsigned index) {
154   assert(index < size());
155   TrailingOperandStorage &storage = getStorage();
156   MutableArrayRef<OpOperand> operands = storage.getOperands();
157   --storage.numOperands;
158 
159   // Shift all operands down by 1 if the operand to remove is not at the end.
160   auto indexIt = std::next(operands.begin(), index);
161   if (index != storage.numOperands)
162     std::rotate(indexIt, std::next(indexIt), operands.end());
163   operands[storage.numOperands].~OpOperand();
164 }
165 
166 //===----------------------------------------------------------------------===//
167 // ResultStorage
168 //===----------------------------------------------------------------------===//
169 
170 /// Returns the parent operation of this trailing result.
171 Operation *detail::TrailingOpResult::getOwner() {
172   // We need to do some arithmetic to get the operation pointer. Move the
173   // trailing owner to the start of the array.
174   TrailingOpResult *trailingIt = this - trailingResultNumber;
175 
176   // Move the owner past the inline op results to get to the operation.
177   auto *inlineResultIt = reinterpret_cast<InLineOpResult *>(trailingIt) -
178                          OpResult::getMaxInlineResults();
179   return reinterpret_cast<Operation *>(inlineResultIt) - 1;
180 }
181 
182 //===----------------------------------------------------------------------===//
183 // Operation Value-Iterators
184 //===----------------------------------------------------------------------===//
185 
186 //===----------------------------------------------------------------------===//
187 // TypeRange
188 
189 TypeRange::TypeRange(ArrayRef<Type> types)
190     : TypeRange(types.data(), types.size()) {}
191 TypeRange::TypeRange(OperandRange values)
192     : TypeRange(values.begin().getBase(), values.size()) {}
193 TypeRange::TypeRange(ResultRange values)
194     : TypeRange(values.getBase()->getResultTypes().slice(values.getStartIndex(),
195                                                          values.size())) {}
196 TypeRange::TypeRange(ArrayRef<Value> values)
197     : TypeRange(values.data(), values.size()) {}
198 TypeRange::TypeRange(ValueRange values) : TypeRange(OwnerT(), values.size()) {
199   detail::ValueRangeOwner owner = values.begin().getBase();
200   if (auto *op = reinterpret_cast<Operation *>(owner.ptr.dyn_cast<void *>()))
201     this->base = op->getResultTypes().drop_front(owner.startIndex).data();
202   else if (auto *operand = owner.ptr.dyn_cast<OpOperand *>())
203     this->base = operand;
204   else
205     this->base = owner.ptr.get<const Value *>();
206 }
207 
208 /// See `llvm::detail::indexed_accessor_range_base` for details.
209 TypeRange::OwnerT TypeRange::offset_base(OwnerT object, ptrdiff_t index) {
210   if (auto *value = object.dyn_cast<const Value *>())
211     return {value + index};
212   if (auto *operand = object.dyn_cast<OpOperand *>())
213     return {operand + index};
214   return {object.dyn_cast<const Type *>() + index};
215 }
216 /// See `llvm::detail::indexed_accessor_range_base` for details.
217 Type TypeRange::dereference_iterator(OwnerT object, ptrdiff_t index) {
218   if (auto *value = object.dyn_cast<const Value *>())
219     return (value + index)->getType();
220   if (auto *operand = object.dyn_cast<OpOperand *>())
221     return (operand + index)->get().getType();
222   return object.dyn_cast<const Type *>()[index];
223 }
224 
225 //===----------------------------------------------------------------------===//
226 // OperandRange
227 
228 OperandRange::OperandRange(Operation *op)
229     : OperandRange(op->getOpOperands().data(), op->getNumOperands()) {}
230 
231 /// Return the operand index of the first element of this range. The range
232 /// must not be empty.
233 unsigned OperandRange::getBeginOperandIndex() const {
234   assert(!empty() && "range must not be empty");
235   return base->getOperandNumber();
236 }
237 
238 //===----------------------------------------------------------------------===//
239 // ResultRange
240 
241 ResultRange::ResultRange(Operation *op)
242     : ResultRange(op, /*startIndex=*/0, op->getNumResults()) {}
243 
244 ArrayRef<Type> ResultRange::getTypes() const {
245   return getBase()->getResultTypes().slice(getStartIndex(), size());
246 }
247 
248 /// See `llvm::indexed_accessor_range` for details.
249 OpResult ResultRange::dereference(Operation *op, ptrdiff_t index) {
250   return op->getResult(index);
251 }
252 
253 //===----------------------------------------------------------------------===//
254 // ValueRange
255 
256 ValueRange::ValueRange(ArrayRef<Value> values)
257     : ValueRange(values.data(), values.size()) {}
258 ValueRange::ValueRange(OperandRange values)
259     : ValueRange(values.begin().getBase(), values.size()) {}
260 ValueRange::ValueRange(ResultRange values)
261     : ValueRange(
262           {values.getBase(), static_cast<unsigned>(values.getStartIndex())},
263           values.size()) {}
264 
265 /// See `llvm::detail::indexed_accessor_range_base` for details.
266 ValueRange::OwnerT ValueRange::offset_base(const OwnerT &owner,
267                                            ptrdiff_t index) {
268   if (auto *value = owner.ptr.dyn_cast<const Value *>())
269     return {value + index};
270   if (auto *operand = owner.ptr.dyn_cast<OpOperand *>())
271     return {operand + index};
272   Operation *operation = reinterpret_cast<Operation *>(owner.ptr.get<void *>());
273   return {operation, owner.startIndex + static_cast<unsigned>(index)};
274 }
275 /// See `llvm::detail::indexed_accessor_range_base` for details.
276 Value ValueRange::dereference_iterator(const OwnerT &owner, ptrdiff_t index) {
277   if (auto *value = owner.ptr.dyn_cast<const Value *>())
278     return value[index];
279   if (auto *operand = owner.ptr.dyn_cast<OpOperand *>())
280     return operand[index].get();
281   Operation *operation = reinterpret_cast<Operation *>(owner.ptr.get<void *>());
282   return operation->getResult(owner.startIndex + index);
283 }
284