1a7215a90SAlex Zinenko //===- OperationSupport.cpp -----------------------------------------------===//
2a7215a90SAlex Zinenko //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7215a90SAlex Zinenko //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
8a7215a90SAlex Zinenko //
9a7215a90SAlex Zinenko // This file contains out-of-line implementations of the support types that
109ffdc930SRiver Riddle // Operation and related classes build on top of.
11a7215a90SAlex Zinenko //
12a7215a90SAlex Zinenko //===----------------------------------------------------------------------===//
13a7215a90SAlex Zinenko 
14a7215a90SAlex Zinenko #include "mlir/IR/OperationSupport.h"
15a7215a90SAlex Zinenko #include "mlir/IR/Block.h"
16108abd2fSRiver Riddle #include "mlir/IR/OpDefinition.h"
179ffdc930SRiver Riddle #include "mlir/IR/Operation.h"
18108abd2fSRiver Riddle #include "mlir/IR/StandardTypes.h"
199ffdc930SRiver Riddle using namespace mlir;
20a7215a90SAlex Zinenko 
219ffdc930SRiver Riddle //===----------------------------------------------------------------------===//
229ffdc930SRiver Riddle // OperationState
239ffdc930SRiver Riddle //===----------------------------------------------------------------------===//
24a7215a90SAlex Zinenko 
2548d6cf1cSRiver Riddle OperationState::OperationState(Location location, StringRef name)
262f59f768SRiver Riddle     : location(location), name(name, location->getContext()) {}
27a7215a90SAlex Zinenko 
2848d6cf1cSRiver Riddle OperationState::OperationState(Location location, OperationName name)
292f59f768SRiver Riddle     : location(location), name(name) {}
30a7215a90SAlex Zinenko 
3148d6cf1cSRiver Riddle OperationState::OperationState(Location location, StringRef name,
32a63f6e0bSUday Bondhugula                                ValueRange operands, ArrayRef<Type> types,
33a7215a90SAlex Zinenko                                ArrayRef<NamedAttribute> attributes,
34a7215a90SAlex Zinenko                                ArrayRef<Block *> successors,
354dfd1b5fSRiver Riddle                                MutableArrayRef<std::unique_ptr<Region>> regions)
362f59f768SRiver Riddle     : location(location), name(name, location->getContext()),
37a7215a90SAlex Zinenko       operands(operands.begin(), operands.end()),
38a7215a90SAlex Zinenko       types(types.begin(), types.end()),
39a7215a90SAlex Zinenko       attributes(attributes.begin(), attributes.end()),
40a7215a90SAlex Zinenko       successors(successors.begin(), successors.end()) {
412f59f768SRiver Riddle   for (std::unique_ptr<Region> &r : regions)
42a7215a90SAlex Zinenko     this->regions.push_back(std::move(r));
43a7215a90SAlex Zinenko }
44a7215a90SAlex Zinenko 
45d6ee6a03SRiver Riddle void OperationState::addOperands(ValueRange newOperands) {
46d6ee6a03SRiver Riddle   operands.append(newOperands.begin(), newOperands.end());
47d6ee6a03SRiver Riddle }
48d6ee6a03SRiver Riddle 
49cb177712SRiver Riddle void OperationState::addSuccessors(SuccessorRange newSuccessors) {
50cb177712SRiver Riddle   successors.append(newSuccessors.begin(), newSuccessors.end());
51d6ee6a03SRiver Riddle }
52d6ee6a03SRiver Riddle 
53a7215a90SAlex Zinenko Region *OperationState::addRegion() {
54a7215a90SAlex Zinenko   regions.emplace_back(new Region);
55a7215a90SAlex Zinenko   return regions.back().get();
56a7215a90SAlex Zinenko }
57a7215a90SAlex Zinenko 
58a7215a90SAlex Zinenko void OperationState::addRegion(std::unique_ptr<Region> &&region) {
59a7215a90SAlex Zinenko   regions.push_back(std::move(region));
60a7215a90SAlex Zinenko }
61a7215a90SAlex Zinenko 
629ffdc930SRiver Riddle //===----------------------------------------------------------------------===//
639ffdc930SRiver Riddle // OperandStorage
649ffdc930SRiver Riddle //===----------------------------------------------------------------------===//
659ffdc930SRiver Riddle 
664dfd1b5fSRiver Riddle detail::OperandStorage::OperandStorage(Operation *owner, ValueRange values)
674dfd1b5fSRiver Riddle     : representation(0) {
684dfd1b5fSRiver Riddle   auto &inlineStorage = getInlineStorage();
694dfd1b5fSRiver Riddle   inlineStorage.numOperands = inlineStorage.capacity = values.size();
704dfd1b5fSRiver Riddle   auto *operandPtrBegin = getTrailingObjects<OpOperand>();
714dfd1b5fSRiver Riddle   for (unsigned i = 0, e = inlineStorage.numOperands; i < e; ++i)
724dfd1b5fSRiver Riddle     new (&operandPtrBegin[i]) OpOperand(owner, values[i]);
734dfd1b5fSRiver Riddle }
744dfd1b5fSRiver Riddle 
754dfd1b5fSRiver Riddle detail::OperandStorage::~OperandStorage() {
764dfd1b5fSRiver Riddle   // Destruct the current storage container.
774dfd1b5fSRiver Riddle   if (isDynamicStorage()) {
784dfd1b5fSRiver Riddle     TrailingOperandStorage &storage = getDynamicStorage();
794dfd1b5fSRiver Riddle     storage.~TrailingOperandStorage();
804dfd1b5fSRiver Riddle     free(&storage);
814dfd1b5fSRiver Riddle   } else {
824dfd1b5fSRiver Riddle     getInlineStorage().~TrailingOperandStorage();
834dfd1b5fSRiver Riddle   }
844dfd1b5fSRiver Riddle }
854dfd1b5fSRiver Riddle 
869ffdc930SRiver Riddle /// Replace the operands contained in the storage with the ones provided in
874dfd1b5fSRiver Riddle /// 'values'.
884dfd1b5fSRiver Riddle void detail::OperandStorage::setOperands(Operation *owner, ValueRange values) {
894dfd1b5fSRiver Riddle   MutableArrayRef<OpOperand> storageOperands = resize(owner, values.size());
904dfd1b5fSRiver Riddle   for (unsigned i = 0, e = values.size(); i != e; ++i)
914dfd1b5fSRiver Riddle     storageOperands[i].set(values[i]);
924dfd1b5fSRiver Riddle }
934dfd1b5fSRiver Riddle 
94108abd2fSRiver Riddle /// Replace the operands beginning at 'start' and ending at 'start' + 'length'
95108abd2fSRiver Riddle /// with the ones provided in 'operands'. 'operands' may be smaller or larger
96108abd2fSRiver Riddle /// than the range pointed to by 'start'+'length'.
97108abd2fSRiver Riddle void detail::OperandStorage::setOperands(Operation *owner, unsigned start,
98108abd2fSRiver Riddle                                          unsigned length, ValueRange operands) {
99108abd2fSRiver Riddle   // If the new size is the same, we can update inplace.
100108abd2fSRiver Riddle   unsigned newSize = operands.size();
101108abd2fSRiver Riddle   if (newSize == length) {
102108abd2fSRiver Riddle     MutableArrayRef<OpOperand> storageOperands = getOperands();
103108abd2fSRiver Riddle     for (unsigned i = 0, e = length; i != e; ++i)
104108abd2fSRiver Riddle       storageOperands[start + i].set(operands[i]);
105108abd2fSRiver Riddle     return;
106108abd2fSRiver Riddle   }
107108abd2fSRiver Riddle   // If the new size is greater, remove the extra operands and set the rest
108108abd2fSRiver Riddle   // inplace.
109108abd2fSRiver Riddle   if (newSize < length) {
110108abd2fSRiver Riddle     eraseOperands(start + operands.size(), length - newSize);
111108abd2fSRiver Riddle     setOperands(owner, start, newSize, operands);
112108abd2fSRiver Riddle     return;
113108abd2fSRiver Riddle   }
114108abd2fSRiver Riddle   // Otherwise, the new size is greater so we need to grow the storage.
115108abd2fSRiver Riddle   auto storageOperands = resize(owner, size() + (newSize - length));
116108abd2fSRiver Riddle 
117108abd2fSRiver Riddle   // Shift operands to the right to make space for the new operands.
118108abd2fSRiver Riddle   unsigned rotateSize = storageOperands.size() - (start + length);
119108abd2fSRiver Riddle   auto rbegin = storageOperands.rbegin();
120108abd2fSRiver Riddle   std::rotate(rbegin, std::next(rbegin, newSize - length), rbegin + rotateSize);
121108abd2fSRiver Riddle 
122108abd2fSRiver Riddle   // Update the operands inplace.
123108abd2fSRiver Riddle   for (unsigned i = 0, e = operands.size(); i != e; ++i)
124108abd2fSRiver Riddle     storageOperands[start + i].set(operands[i]);
125108abd2fSRiver Riddle }
126108abd2fSRiver Riddle 
127108abd2fSRiver Riddle /// Erase an operand held by the storage.
128108abd2fSRiver Riddle void detail::OperandStorage::eraseOperands(unsigned start, unsigned length) {
129108abd2fSRiver Riddle   TrailingOperandStorage &storage = getStorage();
130108abd2fSRiver Riddle   MutableArrayRef<OpOperand> operands = storage.getOperands();
131108abd2fSRiver Riddle   assert((start + length) <= operands.size());
132108abd2fSRiver Riddle   storage.numOperands -= length;
133108abd2fSRiver Riddle 
134108abd2fSRiver Riddle   // Shift all operands down if the operand to remove is not at the end.
135108abd2fSRiver Riddle   if (start != storage.numOperands) {
136108abd2fSRiver Riddle     auto indexIt = std::next(operands.begin(), start);
137108abd2fSRiver Riddle     std::rotate(indexIt, std::next(indexIt, length), operands.end());
138108abd2fSRiver Riddle   }
139108abd2fSRiver Riddle   for (unsigned i = 0; i != length; ++i)
140108abd2fSRiver Riddle     operands[storage.numOperands + i].~OpOperand();
141108abd2fSRiver Riddle }
142108abd2fSRiver Riddle 
1434dfd1b5fSRiver Riddle /// Resize the storage to the given size. Returns the array containing the new
1444dfd1b5fSRiver Riddle /// operands.
1454dfd1b5fSRiver Riddle MutableArrayRef<OpOperand> detail::OperandStorage::resize(Operation *owner,
1464dfd1b5fSRiver Riddle                                                           unsigned newSize) {
1474dfd1b5fSRiver Riddle   TrailingOperandStorage &storage = getStorage();
1484dfd1b5fSRiver Riddle 
1499ffdc930SRiver Riddle   // If the number of operands is less than or equal to the current amount, we
1509ffdc930SRiver Riddle   // can just update in place.
1514dfd1b5fSRiver Riddle   unsigned &numOperands = storage.numOperands;
1524dfd1b5fSRiver Riddle   MutableArrayRef<OpOperand> operands = storage.getOperands();
1534dfd1b5fSRiver Riddle   if (newSize <= numOperands) {
1544dfd1b5fSRiver Riddle     // If the number of new size is less than the current, remove any extra
1554dfd1b5fSRiver Riddle     // operands.
1564dfd1b5fSRiver Riddle     for (unsigned i = newSize; i != numOperands; ++i)
1574dfd1b5fSRiver Riddle       operands[i].~OpOperand();
1584dfd1b5fSRiver Riddle     numOperands = newSize;
1594dfd1b5fSRiver Riddle     return operands.take_front(newSize);
1609ffdc930SRiver Riddle   }
1619ffdc930SRiver Riddle 
1624dfd1b5fSRiver Riddle   // If the new size is within the original inline capacity, grow inplace.
1634dfd1b5fSRiver Riddle   if (newSize <= storage.capacity) {
1644dfd1b5fSRiver Riddle     OpOperand *opBegin = operands.data();
1654dfd1b5fSRiver Riddle     for (unsigned e = newSize; numOperands != e; ++numOperands)
1664dfd1b5fSRiver Riddle       new (&opBegin[numOperands]) OpOperand(owner);
1674dfd1b5fSRiver Riddle     return MutableArrayRef<OpOperand>(opBegin, newSize);
1688da0f85eSRiver Riddle   }
1699ffdc930SRiver Riddle 
1704dfd1b5fSRiver Riddle   // Otherwise, we need to allocate a new storage.
1714dfd1b5fSRiver Riddle   unsigned newCapacity =
1724dfd1b5fSRiver Riddle       std::max(unsigned(llvm::NextPowerOf2(storage.capacity + 2)), newSize);
1734dfd1b5fSRiver Riddle   auto *newStorageMem =
1744dfd1b5fSRiver Riddle       malloc(TrailingOperandStorage::totalSizeToAlloc<OpOperand>(newCapacity));
1754dfd1b5fSRiver Riddle   auto *newStorage = ::new (newStorageMem) TrailingOperandStorage();
1764dfd1b5fSRiver Riddle   newStorage->numOperands = newSize;
1774dfd1b5fSRiver Riddle   newStorage->capacity = newCapacity;
1784dfd1b5fSRiver Riddle 
1794dfd1b5fSRiver Riddle   // Move the current operands to the new storage.
1804dfd1b5fSRiver Riddle   MutableArrayRef<OpOperand> newOperands = newStorage->getOperands();
1814dfd1b5fSRiver Riddle   std::uninitialized_copy(std::make_move_iterator(operands.begin()),
1824dfd1b5fSRiver Riddle                           std::make_move_iterator(operands.end()),
1834dfd1b5fSRiver Riddle                           newOperands.begin());
1844dfd1b5fSRiver Riddle 
1854dfd1b5fSRiver Riddle   // Destroy the original operands.
1864dfd1b5fSRiver Riddle   for (auto &operand : operands)
1874dfd1b5fSRiver Riddle     operand.~OpOperand();
1884dfd1b5fSRiver Riddle 
1894dfd1b5fSRiver Riddle   // Initialize any new operands.
1904dfd1b5fSRiver Riddle   for (unsigned e = newSize; numOperands != e; ++numOperands)
1914dfd1b5fSRiver Riddle     new (&newOperands[numOperands]) OpOperand(owner);
1924dfd1b5fSRiver Riddle 
1934dfd1b5fSRiver Riddle   // If the current storage is also dynamic, free it.
1944dfd1b5fSRiver Riddle   if (isDynamicStorage())
1954dfd1b5fSRiver Riddle     free(&storage);
1964dfd1b5fSRiver Riddle 
1974dfd1b5fSRiver Riddle   // Update the storage representation to use the new dynamic storage.
1984dfd1b5fSRiver Riddle   representation = reinterpret_cast<intptr_t>(newStorage);
1994dfd1b5fSRiver Riddle   representation |= DynamicStorageBit;
2004dfd1b5fSRiver Riddle   return newOperands;
2019ffdc930SRiver Riddle }
2029ffdc930SRiver Riddle 
2039ed22ae5SRiver Riddle //===----------------------------------------------------------------------===//
20448e9ef43SRiver Riddle // ResultStorage
20548e9ef43SRiver Riddle //===----------------------------------------------------------------------===//
20648e9ef43SRiver Riddle 
20748e9ef43SRiver Riddle /// Returns the parent operation of this trailing result.
20848e9ef43SRiver Riddle Operation *detail::TrailingOpResult::getOwner() {
20948e9ef43SRiver Riddle   // We need to do some arithmetic to get the operation pointer. Move the
21048e9ef43SRiver Riddle   // trailing owner to the start of the array.
21148e9ef43SRiver Riddle   TrailingOpResult *trailingIt = this - trailingResultNumber;
21248e9ef43SRiver Riddle 
21348e9ef43SRiver Riddle   // Move the owner past the inline op results to get to the operation.
21448e9ef43SRiver Riddle   auto *inlineResultIt = reinterpret_cast<InLineOpResult *>(trailingIt) -
21548e9ef43SRiver Riddle                          OpResult::getMaxInlineResults();
21648e9ef43SRiver Riddle   return reinterpret_cast<Operation *>(inlineResultIt) - 1;
21748e9ef43SRiver Riddle }
21848e9ef43SRiver Riddle 
21948e9ef43SRiver Riddle //===----------------------------------------------------------------------===//
2209ed22ae5SRiver Riddle // Operation Value-Iterators
2219ed22ae5SRiver Riddle //===----------------------------------------------------------------------===//
2229ed22ae5SRiver Riddle 
2239ed22ae5SRiver Riddle //===----------------------------------------------------------------------===//
22494a4ca4bSRiver Riddle // TypeRange
22594a4ca4bSRiver Riddle 
22694a4ca4bSRiver Riddle TypeRange::TypeRange(ArrayRef<Type> types)
22794a4ca4bSRiver Riddle     : TypeRange(types.data(), types.size()) {}
22894a4ca4bSRiver Riddle TypeRange::TypeRange(OperandRange values)
22994a4ca4bSRiver Riddle     : TypeRange(values.begin().getBase(), values.size()) {}
23094a4ca4bSRiver Riddle TypeRange::TypeRange(ResultRange values)
23194a4ca4bSRiver Riddle     : TypeRange(values.getBase()->getResultTypes().slice(values.getStartIndex(),
23294a4ca4bSRiver Riddle                                                          values.size())) {}
233988249a5SRiver Riddle TypeRange::TypeRange(ArrayRef<Value> values)
234988249a5SRiver Riddle     : TypeRange(values.data(), values.size()) {}
23594a4ca4bSRiver Riddle TypeRange::TypeRange(ValueRange values) : TypeRange(OwnerT(), values.size()) {
23694a4ca4bSRiver Riddle   detail::ValueRangeOwner owner = values.begin().getBase();
23794a4ca4bSRiver Riddle   if (auto *op = reinterpret_cast<Operation *>(owner.ptr.dyn_cast<void *>()))
238b87531caSRiver Riddle     this->base = op->getResultTypes().drop_front(owner.startIndex).data();
23994a4ca4bSRiver Riddle   else if (auto *operand = owner.ptr.dyn_cast<OpOperand *>())
24094a4ca4bSRiver Riddle     this->base = operand;
24194a4ca4bSRiver Riddle   else
24294a4ca4bSRiver Riddle     this->base = owner.ptr.get<const Value *>();
24394a4ca4bSRiver Riddle }
24494a4ca4bSRiver Riddle 
245204c3b55SRiver Riddle /// See `llvm::detail::indexed_accessor_range_base` for details.
24694a4ca4bSRiver Riddle TypeRange::OwnerT TypeRange::offset_base(OwnerT object, ptrdiff_t index) {
24794a4ca4bSRiver Riddle   if (auto *value = object.dyn_cast<const Value *>())
24894a4ca4bSRiver Riddle     return {value + index};
24994a4ca4bSRiver Riddle   if (auto *operand = object.dyn_cast<OpOperand *>())
25094a4ca4bSRiver Riddle     return {operand + index};
25194a4ca4bSRiver Riddle   return {object.dyn_cast<const Type *>() + index};
25294a4ca4bSRiver Riddle }
253204c3b55SRiver Riddle /// See `llvm::detail::indexed_accessor_range_base` for details.
25494a4ca4bSRiver Riddle Type TypeRange::dereference_iterator(OwnerT object, ptrdiff_t index) {
25594a4ca4bSRiver Riddle   if (auto *value = object.dyn_cast<const Value *>())
25694a4ca4bSRiver Riddle     return (value + index)->getType();
25794a4ca4bSRiver Riddle   if (auto *operand = object.dyn_cast<OpOperand *>())
25894a4ca4bSRiver Riddle     return (operand + index)->get().getType();
25994a4ca4bSRiver Riddle   return object.dyn_cast<const Type *>()[index];
26094a4ca4bSRiver Riddle }
26194a4ca4bSRiver Riddle 
26294a4ca4bSRiver Riddle //===----------------------------------------------------------------------===//
2639ed22ae5SRiver Riddle // OperandRange
2649ed22ae5SRiver Riddle 
2659ed22ae5SRiver Riddle OperandRange::OperandRange(Operation *op)
2669ed22ae5SRiver Riddle     : OperandRange(op->getOpOperands().data(), op->getNumOperands()) {}
2679ed22ae5SRiver Riddle 
268621d7ccaSRiver Riddle /// Return the operand index of the first element of this range. The range
269621d7ccaSRiver Riddle /// must not be empty.
270621d7ccaSRiver Riddle unsigned OperandRange::getBeginOperandIndex() const {
271621d7ccaSRiver Riddle   assert(!empty() && "range must not be empty");
272621d7ccaSRiver Riddle   return base->getOperandNumber();
273621d7ccaSRiver Riddle }
274621d7ccaSRiver Riddle 
2759ed22ae5SRiver Riddle //===----------------------------------------------------------------------===//
276108abd2fSRiver Riddle // MutableOperandRange
277108abd2fSRiver Riddle 
278108abd2fSRiver Riddle /// Construct a new mutable range from the given operand, operand start index,
279108abd2fSRiver Riddle /// and range length.
280108abd2fSRiver Riddle MutableOperandRange::MutableOperandRange(
281108abd2fSRiver Riddle     Operation *owner, unsigned start, unsigned length,
282108abd2fSRiver Riddle     ArrayRef<OperandSegment> operandSegments)
283108abd2fSRiver Riddle     : owner(owner), start(start), length(length),
284108abd2fSRiver Riddle       operandSegments(operandSegments.begin(), operandSegments.end()) {
285108abd2fSRiver Riddle   assert((start + length) <= owner->getNumOperands() && "invalid range");
286108abd2fSRiver Riddle }
287108abd2fSRiver Riddle MutableOperandRange::MutableOperandRange(Operation *owner)
288108abd2fSRiver Riddle     : MutableOperandRange(owner, /*start=*/0, owner->getNumOperands()) {}
289108abd2fSRiver Riddle 
290108abd2fSRiver Riddle /// Append the given values to the range.
291108abd2fSRiver Riddle void MutableOperandRange::append(ValueRange values) {
292108abd2fSRiver Riddle   if (values.empty())
293108abd2fSRiver Riddle     return;
294108abd2fSRiver Riddle   owner->insertOperands(start + length, values);
295108abd2fSRiver Riddle   updateLength(length + values.size());
296108abd2fSRiver Riddle }
297108abd2fSRiver Riddle 
298108abd2fSRiver Riddle /// Assign this range to the given values.
299108abd2fSRiver Riddle void MutableOperandRange::assign(ValueRange values) {
300108abd2fSRiver Riddle   owner->setOperands(start, length, values);
301108abd2fSRiver Riddle   if (length != values.size())
302108abd2fSRiver Riddle     updateLength(/*newLength=*/values.size());
303108abd2fSRiver Riddle }
304108abd2fSRiver Riddle 
305108abd2fSRiver Riddle /// Assign the range to the given value.
306108abd2fSRiver Riddle void MutableOperandRange::assign(Value value) {
307108abd2fSRiver Riddle   if (length == 1) {
308108abd2fSRiver Riddle     owner->setOperand(start, value);
309108abd2fSRiver Riddle   } else {
310108abd2fSRiver Riddle     owner->setOperands(start, length, value);
311108abd2fSRiver Riddle     updateLength(/*newLength=*/1);
312108abd2fSRiver Riddle   }
313108abd2fSRiver Riddle }
314108abd2fSRiver Riddle 
315108abd2fSRiver Riddle /// Erase the operands within the given sub-range.
316108abd2fSRiver Riddle void MutableOperandRange::erase(unsigned subStart, unsigned subLen) {
317108abd2fSRiver Riddle   assert((subStart + subLen) <= length && "invalid sub-range");
318108abd2fSRiver Riddle   if (length == 0)
319108abd2fSRiver Riddle     return;
320108abd2fSRiver Riddle   owner->eraseOperands(start + subStart, subLen);
321108abd2fSRiver Riddle   updateLength(length - subLen);
322108abd2fSRiver Riddle }
323108abd2fSRiver Riddle 
324108abd2fSRiver Riddle /// Clear this range and erase all of the operands.
325108abd2fSRiver Riddle void MutableOperandRange::clear() {
326108abd2fSRiver Riddle   if (length != 0) {
327108abd2fSRiver Riddle     owner->eraseOperands(start, length);
328108abd2fSRiver Riddle     updateLength(/*newLength=*/0);
329108abd2fSRiver Riddle   }
330108abd2fSRiver Riddle }
331108abd2fSRiver Riddle 
332108abd2fSRiver Riddle /// Allow implicit conversion to an OperandRange.
333108abd2fSRiver Riddle MutableOperandRange::operator OperandRange() const {
334108abd2fSRiver Riddle   return owner->getOperands().slice(start, length);
335108abd2fSRiver Riddle }
336108abd2fSRiver Riddle 
337108abd2fSRiver Riddle /// Update the length of this range to the one provided.
338108abd2fSRiver Riddle void MutableOperandRange::updateLength(unsigned newLength) {
339108abd2fSRiver Riddle   int32_t diff = int32_t(newLength) - int32_t(length);
340108abd2fSRiver Riddle   length = newLength;
341108abd2fSRiver Riddle 
342108abd2fSRiver Riddle   // Update any of the provided segment attributes.
343108abd2fSRiver Riddle   for (OperandSegment &segment : operandSegments) {
344108abd2fSRiver Riddle     auto attr = segment.second.second.cast<DenseIntElementsAttr>();
345108abd2fSRiver Riddle     SmallVector<int32_t, 8> segments(attr.getValues<int32_t>());
346108abd2fSRiver Riddle     segments[segment.first] += diff;
347108abd2fSRiver Riddle     segment.second.second = DenseIntElementsAttr::get(attr.getType(), segments);
348108abd2fSRiver Riddle     owner->setAttr(segment.second.first, segment.second.second);
349108abd2fSRiver Riddle   }
350108abd2fSRiver Riddle }
351108abd2fSRiver Riddle 
352108abd2fSRiver Riddle //===----------------------------------------------------------------------===//
3539ed22ae5SRiver Riddle // ResultRange
3549ed22ae5SRiver Riddle 
3559ed22ae5SRiver Riddle ResultRange::ResultRange(Operation *op)
356fd01d862SRiver Riddle     : ResultRange(op, /*startIndex=*/0, op->getNumResults()) {}
357fd01d862SRiver Riddle 
358aff4ed73SRiver Riddle ArrayRef<Type> ResultRange::getTypes() const {
359b87531caSRiver Riddle   return getBase()->getResultTypes().slice(getStartIndex(), size());
360aff4ed73SRiver Riddle }
361aff4ed73SRiver Riddle 
362204c3b55SRiver Riddle /// See `llvm::indexed_accessor_range` for details.
3630d9ca98cSRiver Riddle OpResult ResultRange::dereference(Operation *op, ptrdiff_t index) {
364fd01d862SRiver Riddle   return op->getResult(index);
365fd01d862SRiver Riddle }
3669ed22ae5SRiver Riddle 
3679ed22ae5SRiver Riddle //===----------------------------------------------------------------------===//
3689ed22ae5SRiver Riddle // ValueRange
3699ed22ae5SRiver Riddle 
370ab46543cSRiver Riddle ValueRange::ValueRange(ArrayRef<Value> values)
3719ed22ae5SRiver Riddle     : ValueRange(values.data(), values.size()) {}
3729ed22ae5SRiver Riddle ValueRange::ValueRange(OperandRange values)
3739ed22ae5SRiver Riddle     : ValueRange(values.begin().getBase(), values.size()) {}
3749ed22ae5SRiver Riddle ValueRange::ValueRange(ResultRange values)
375fd01d862SRiver Riddle     : ValueRange(
376fd01d862SRiver Riddle           {values.getBase(), static_cast<unsigned>(values.getStartIndex())},
377fd01d862SRiver Riddle           values.size()) {}
3789ed22ae5SRiver Riddle 
379204c3b55SRiver Riddle /// See `llvm::detail::indexed_accessor_range_base` for details.
3809ed22ae5SRiver Riddle ValueRange::OwnerT ValueRange::offset_base(const OwnerT &owner,
3819ed22ae5SRiver Riddle                                            ptrdiff_t index) {
382fd01d862SRiver Riddle   if (auto *value = owner.ptr.dyn_cast<const Value *>())
383fd01d862SRiver Riddle     return {value + index};
384fd01d862SRiver Riddle   if (auto *operand = owner.ptr.dyn_cast<OpOperand *>())
385fd01d862SRiver Riddle     return {operand + index};
386fd01d862SRiver Riddle   Operation *operation = reinterpret_cast<Operation *>(owner.ptr.get<void *>());
387fd01d862SRiver Riddle   return {operation, owner.startIndex + static_cast<unsigned>(index)};
3889ed22ae5SRiver Riddle }
389204c3b55SRiver Riddle /// See `llvm::detail::indexed_accessor_range_base` for details.
390ab46543cSRiver Riddle Value ValueRange::dereference_iterator(const OwnerT &owner, ptrdiff_t index) {
391fd01d862SRiver Riddle   if (auto *value = owner.ptr.dyn_cast<const Value *>())
392fd01d862SRiver Riddle     return value[index];
393fd01d862SRiver Riddle   if (auto *operand = owner.ptr.dyn_cast<OpOperand *>())
3949ed22ae5SRiver Riddle     return operand[index].get();
395fd01d862SRiver Riddle   Operation *operation = reinterpret_cast<Operation *>(owner.ptr.get<void *>());
396fd01d862SRiver Riddle   return operation->getResult(owner.startIndex + index);
3979ed22ae5SRiver Riddle }
398*df00e466SRiver Riddle 
399*df00e466SRiver Riddle //===----------------------------------------------------------------------===//
400*df00e466SRiver Riddle // Operation Equivalency
401*df00e466SRiver Riddle //===----------------------------------------------------------------------===//
402*df00e466SRiver Riddle 
403*df00e466SRiver Riddle llvm::hash_code OperationEquivalence::computeHash(Operation *op) {
404*df00e466SRiver Riddle   // Hash operations based upon their:
405*df00e466SRiver Riddle   //   - Operation Name
406*df00e466SRiver Riddle   //   - Attributes
407*df00e466SRiver Riddle   llvm::hash_code hash = llvm::hash_combine(
408*df00e466SRiver Riddle       op->getName(), op->getMutableAttrDict().getDictionary());
409*df00e466SRiver Riddle 
410*df00e466SRiver Riddle   //   - Result Types
411*df00e466SRiver Riddle   ArrayRef<Type> resultTypes = op->getResultTypes();
412*df00e466SRiver Riddle   switch (resultTypes.size()) {
413*df00e466SRiver Riddle   case 0:
414*df00e466SRiver Riddle     // We don't need to add anything to the hash.
415*df00e466SRiver Riddle     break;
416*df00e466SRiver Riddle   case 1:
417*df00e466SRiver Riddle     // Add in the result type.
418*df00e466SRiver Riddle     hash = llvm::hash_combine(hash, resultTypes.front());
419*df00e466SRiver Riddle     break;
420*df00e466SRiver Riddle   default:
421*df00e466SRiver Riddle     // Use the type buffer as the hash, as we can guarantee it is the same for
422*df00e466SRiver Riddle     // any given range of result types. This takes advantage of the fact the
423*df00e466SRiver Riddle     // result types >1 are stored in a TupleType and uniqued.
424*df00e466SRiver Riddle     hash = llvm::hash_combine(hash, resultTypes.data());
425*df00e466SRiver Riddle     break;
426*df00e466SRiver Riddle   }
427*df00e466SRiver Riddle 
428*df00e466SRiver Riddle   //   - Operands
429*df00e466SRiver Riddle   // TODO: Allow commutative operations to have different ordering.
430*df00e466SRiver Riddle   return llvm::hash_combine(
431*df00e466SRiver Riddle       hash, llvm::hash_combine_range(op->operand_begin(), op->operand_end()));
432*df00e466SRiver Riddle }
433*df00e466SRiver Riddle 
434*df00e466SRiver Riddle bool OperationEquivalence::isEquivalentTo(Operation *lhs, Operation *rhs) {
435*df00e466SRiver Riddle   if (lhs == rhs)
436*df00e466SRiver Riddle     return true;
437*df00e466SRiver Riddle 
438*df00e466SRiver Riddle   // Compare the operation name.
439*df00e466SRiver Riddle   if (lhs->getName() != rhs->getName())
440*df00e466SRiver Riddle     return false;
441*df00e466SRiver Riddle   // Check operand counts.
442*df00e466SRiver Riddle   if (lhs->getNumOperands() != rhs->getNumOperands())
443*df00e466SRiver Riddle     return false;
444*df00e466SRiver Riddle   // Compare attributes.
445*df00e466SRiver Riddle   if (lhs->getMutableAttrDict() != rhs->getMutableAttrDict())
446*df00e466SRiver Riddle     return false;
447*df00e466SRiver Riddle   // Compare result types.
448*df00e466SRiver Riddle   ArrayRef<Type> lhsResultTypes = lhs->getResultTypes();
449*df00e466SRiver Riddle   ArrayRef<Type> rhsResultTypes = rhs->getResultTypes();
450*df00e466SRiver Riddle   if (lhsResultTypes.size() != rhsResultTypes.size())
451*df00e466SRiver Riddle     return false;
452*df00e466SRiver Riddle   switch (lhsResultTypes.size()) {
453*df00e466SRiver Riddle   case 0:
454*df00e466SRiver Riddle     break;
455*df00e466SRiver Riddle   case 1:
456*df00e466SRiver Riddle     // Compare the single result type.
457*df00e466SRiver Riddle     if (lhsResultTypes.front() != rhsResultTypes.front())
458*df00e466SRiver Riddle       return false;
459*df00e466SRiver Riddle     break;
460*df00e466SRiver Riddle   default:
461*df00e466SRiver Riddle     // Use the type buffer for the comparison, as we can guarantee it is the
462*df00e466SRiver Riddle     // same for any given range of result types. This takes advantage of the
463*df00e466SRiver Riddle     // fact the result types >1 are stored in a TupleType and uniqued.
464*df00e466SRiver Riddle     if (lhsResultTypes.data() != rhsResultTypes.data())
465*df00e466SRiver Riddle       return false;
466*df00e466SRiver Riddle     break;
467*df00e466SRiver Riddle   }
468*df00e466SRiver Riddle   // Compare operands.
469*df00e466SRiver Riddle   // TODO: Allow commutative operations to have different ordering.
470*df00e466SRiver Riddle   return std::equal(lhs->operand_begin(), lhs->operand_end(),
471*df00e466SRiver Riddle                     rhs->operand_begin());
472*df00e466SRiver Riddle }
473