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                                bool resizableOperandList)
35     : location(location), name(name, location->getContext()),
36       operands(operands.begin(), operands.end()),
37       types(types.begin(), types.end()),
38       attributes(attributes.begin(), attributes.end()),
39       successors(successors.begin(), successors.end()) {
40   for (std::unique_ptr<Region> &r : regions)
41     this->regions.push_back(std::move(r));
42 }
43 
44 void OperationState::addOperands(ValueRange newOperands) {
45   operands.append(newOperands.begin(), newOperands.end());
46 }
47 
48 void OperationState::addSuccessors(SuccessorRange newSuccessors) {
49   successors.append(newSuccessors.begin(), newSuccessors.end());
50 }
51 
52 Region *OperationState::addRegion() {
53   regions.emplace_back(new Region);
54   return regions.back().get();
55 }
56 
57 void OperationState::addRegion(std::unique_ptr<Region> &&region) {
58   regions.push_back(std::move(region));
59 }
60 
61 //===----------------------------------------------------------------------===//
62 // OperandStorage
63 //===----------------------------------------------------------------------===//
64 
65 /// Replace the operands contained in the storage with the ones provided in
66 /// 'operands'.
67 void detail::OperandStorage::setOperands(Operation *owner,
68                                          ValueRange operands) {
69   // If the number of operands is less than or equal to the current amount, we
70   // can just update in place.
71   if (operands.size() <= numOperands) {
72     auto opOperands = getOperands();
73 
74     // If the number of new operands is less than the current count, then remove
75     // any extra operands.
76     for (unsigned i = operands.size(); i != numOperands; ++i)
77       opOperands[i].~OpOperand();
78 
79     // Set the operands in place.
80     numOperands = operands.size();
81     for (unsigned i = 0; i != numOperands; ++i)
82       opOperands[i].set(operands[i]);
83     return;
84   }
85 
86   // Otherwise, we need to be resizable.
87   assert(resizable && "Only resizable operations may add operands");
88 
89   // Grow the capacity if necessary.
90   auto &resizeUtil = getResizableStorage();
91   if (resizeUtil.capacity < operands.size())
92     grow(resizeUtil, operands.size());
93 
94   // Set the operands.
95   OpOperand *opBegin = getRawOperands();
96   for (unsigned i = 0; i != numOperands; ++i)
97     opBegin[i].set(operands[i]);
98   for (unsigned e = operands.size(); numOperands != e; ++numOperands)
99     new (&opBegin[numOperands]) OpOperand(owner, operands[numOperands]);
100 }
101 
102 /// Erase an operand held by the storage.
103 void detail::OperandStorage::eraseOperand(unsigned index) {
104   assert(index < size());
105   auto operands = getOperands();
106   --numOperands;
107 
108   // Shift all operands down by 1 if the operand to remove is not at the end.
109   auto indexIt = std::next(operands.begin(), index);
110   if (index != numOperands)
111     std::rotate(indexIt, std::next(indexIt), operands.end());
112   operands[numOperands].~OpOperand();
113 }
114 
115 /// Grow the internal operand storage.
116 void detail::OperandStorage::grow(ResizableStorage &resizeUtil,
117                                   size_t minSize) {
118   // Allocate a new storage array.
119   resizeUtil.capacity =
120       std::max(size_t(llvm::NextPowerOf2(resizeUtil.capacity + 2)), minSize);
121   OpOperand *newStorage = static_cast<OpOperand *>(
122       llvm::safe_malloc(resizeUtil.capacity * sizeof(OpOperand)));
123 
124   // Move the current operands to the new storage.
125   auto operands = getOperands();
126   std::uninitialized_copy(std::make_move_iterator(operands.begin()),
127                           std::make_move_iterator(operands.end()), newStorage);
128 
129   // Destroy the original operands and update the resizable storage pointer.
130   for (auto &operand : operands)
131     operand.~OpOperand();
132   resizeUtil.setDynamicStorage(newStorage);
133 }
134 
135 //===----------------------------------------------------------------------===//
136 // Operation Value-Iterators
137 //===----------------------------------------------------------------------===//
138 
139 //===----------------------------------------------------------------------===//
140 // TypeRange
141 
142 TypeRange::TypeRange(ArrayRef<Type> types)
143     : TypeRange(types.data(), types.size()) {}
144 TypeRange::TypeRange(OperandRange values)
145     : TypeRange(values.begin().getBase(), values.size()) {}
146 TypeRange::TypeRange(ResultRange values)
147     : TypeRange(values.getBase()->getResultTypes().slice(values.getStartIndex(),
148                                                          values.size())) {}
149 TypeRange::TypeRange(ArrayRef<Value> values)
150     : TypeRange(values.data(), values.size()) {}
151 TypeRange::TypeRange(ValueRange values) : TypeRange(OwnerT(), values.size()) {
152   detail::ValueRangeOwner owner = values.begin().getBase();
153   if (auto *op = reinterpret_cast<Operation *>(owner.ptr.dyn_cast<void *>()))
154     this->base = &op->getResultTypes()[owner.startIndex];
155   else if (auto *operand = owner.ptr.dyn_cast<OpOperand *>())
156     this->base = operand;
157   else
158     this->base = owner.ptr.get<const Value *>();
159 }
160 
161 /// See `detail::indexed_accessor_range_base` for details.
162 TypeRange::OwnerT TypeRange::offset_base(OwnerT object, ptrdiff_t index) {
163   if (auto *value = object.dyn_cast<const Value *>())
164     return {value + index};
165   if (auto *operand = object.dyn_cast<OpOperand *>())
166     return {operand + index};
167   return {object.dyn_cast<const Type *>() + index};
168 }
169 /// See `detail::indexed_accessor_range_base` for details.
170 Type TypeRange::dereference_iterator(OwnerT object, ptrdiff_t index) {
171   if (auto *value = object.dyn_cast<const Value *>())
172     return (value + index)->getType();
173   if (auto *operand = object.dyn_cast<OpOperand *>())
174     return (operand + index)->get().getType();
175   return object.dyn_cast<const Type *>()[index];
176 }
177 
178 //===----------------------------------------------------------------------===//
179 // OperandRange
180 
181 OperandRange::OperandRange(Operation *op)
182     : OperandRange(op->getOpOperands().data(), op->getNumOperands()) {}
183 
184 /// Return the operand index of the first element of this range. The range
185 /// must not be empty.
186 unsigned OperandRange::getBeginOperandIndex() const {
187   assert(!empty() && "range must not be empty");
188   return base->getOperandNumber();
189 }
190 
191 //===----------------------------------------------------------------------===//
192 // ResultRange
193 
194 ResultRange::ResultRange(Operation *op)
195     : ResultRange(op, /*startIndex=*/0, op->getNumResults()) {}
196 
197 ArrayRef<Type> ResultRange::getTypes() const {
198   return getBase()->getResultTypes();
199 }
200 
201 /// See `indexed_accessor_range` for details.
202 OpResult ResultRange::dereference(Operation *op, ptrdiff_t index) {
203   return op->getResult(index);
204 }
205 
206 //===----------------------------------------------------------------------===//
207 // ValueRange
208 
209 ValueRange::ValueRange(ArrayRef<Value> values)
210     : ValueRange(values.data(), values.size()) {}
211 ValueRange::ValueRange(OperandRange values)
212     : ValueRange(values.begin().getBase(), values.size()) {}
213 ValueRange::ValueRange(ResultRange values)
214     : ValueRange(
215           {values.getBase(), static_cast<unsigned>(values.getStartIndex())},
216           values.size()) {}
217 
218 /// See `detail::indexed_accessor_range_base` for details.
219 ValueRange::OwnerT ValueRange::offset_base(const OwnerT &owner,
220                                            ptrdiff_t index) {
221   if (auto *value = owner.ptr.dyn_cast<const Value *>())
222     return {value + index};
223   if (auto *operand = owner.ptr.dyn_cast<OpOperand *>())
224     return {operand + index};
225   Operation *operation = reinterpret_cast<Operation *>(owner.ptr.get<void *>());
226   return {operation, owner.startIndex + static_cast<unsigned>(index)};
227 }
228 /// See `detail::indexed_accessor_range_base` for details.
229 Value ValueRange::dereference_iterator(const OwnerT &owner, ptrdiff_t index) {
230   if (auto *value = owner.ptr.dyn_cast<const Value *>())
231     return value[index];
232   if (auto *operand = owner.ptr.dyn_cast<OpOperand *>())
233     return operand[index].get();
234   Operation *operation = reinterpret_cast<Operation *>(owner.ptr.get<void *>());
235   return operation->getResult(owner.startIndex + index);
236 }
237