1 //===- OperationSupport.cpp -----------------------------------------------===// 2 // 3 // Part of the MLIR 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 assert(successors.empty() && "Non successor operands should be added first."); 46 operands.append(newOperands.begin(), newOperands.end()); 47 } 48 49 void OperationState::addSuccessor(Block *successor, ValueRange succOperands) { 50 successors.push_back(successor); 51 // Insert a sentinel operand to mark a barrier between successor operands. 52 operands.push_back(nullptr); 53 operands.append(succOperands.begin(), succOperands.end()); 54 } 55 56 Region *OperationState::addRegion() { 57 regions.emplace_back(new Region); 58 return regions.back().get(); 59 } 60 61 void OperationState::addRegion(std::unique_ptr<Region> &®ion) { 62 regions.push_back(std::move(region)); 63 } 64 65 //===----------------------------------------------------------------------===// 66 // OperandStorage 67 //===----------------------------------------------------------------------===// 68 69 /// Replace the operands contained in the storage with the ones provided in 70 /// 'operands'. 71 void detail::OperandStorage::setOperands(Operation *owner, 72 ValueRange operands) { 73 // If the number of operands is less than or equal to the current amount, we 74 // can just update in place. 75 if (operands.size() <= numOperands) { 76 auto opOperands = getOperands(); 77 78 // If the number of new operands is less than the current count, then remove 79 // any extra operands. 80 for (unsigned i = operands.size(); i != numOperands; ++i) 81 opOperands[i].~OpOperand(); 82 83 // Set the operands in place. 84 numOperands = operands.size(); 85 for (unsigned i = 0; i != numOperands; ++i) 86 opOperands[i].set(operands[i]); 87 return; 88 } 89 90 // Otherwise, we need to be resizable. 91 assert(resizable && "Only resizable operations may add operands"); 92 93 // Grow the capacity if necessary. 94 auto &resizeUtil = getResizableStorage(); 95 if (resizeUtil.capacity < operands.size()) 96 grow(resizeUtil, operands.size()); 97 98 // Set the operands. 99 OpOperand *opBegin = getRawOperands(); 100 for (unsigned i = 0; i != numOperands; ++i) 101 opBegin[i].set(operands[i]); 102 for (unsigned e = operands.size(); numOperands != e; ++numOperands) 103 new (&opBegin[numOperands]) OpOperand(owner, operands[numOperands]); 104 } 105 106 /// Erase an operand held by the storage. 107 void detail::OperandStorage::eraseOperand(unsigned index) { 108 assert(index < size()); 109 auto operands = getOperands(); 110 --numOperands; 111 112 // Shift all operands down by 1 if the operand to remove is not at the end. 113 auto indexIt = std::next(operands.begin(), index); 114 if (index != numOperands) 115 std::rotate(indexIt, std::next(indexIt), operands.end()); 116 operands[numOperands].~OpOperand(); 117 } 118 119 /// Grow the internal operand storage. 120 void detail::OperandStorage::grow(ResizableStorage &resizeUtil, 121 size_t minSize) { 122 // Allocate a new storage array. 123 resizeUtil.capacity = 124 std::max(size_t(llvm::NextPowerOf2(resizeUtil.capacity + 2)), minSize); 125 OpOperand *newStorage = static_cast<OpOperand *>( 126 llvm::safe_malloc(resizeUtil.capacity * sizeof(OpOperand))); 127 128 // Move the current operands to the new storage. 129 auto operands = getOperands(); 130 std::uninitialized_copy(std::make_move_iterator(operands.begin()), 131 std::make_move_iterator(operands.end()), newStorage); 132 133 // Destroy the original operands and update the resizable storage pointer. 134 for (auto &operand : operands) 135 operand.~OpOperand(); 136 resizeUtil.setDynamicStorage(newStorage); 137 } 138 139 //===----------------------------------------------------------------------===// 140 // Operation Value-Iterators 141 //===----------------------------------------------------------------------===// 142 143 //===----------------------------------------------------------------------===// 144 // OperandRange 145 146 OperandRange::OperandRange(Operation *op) 147 : OperandRange(op->getOpOperands().data(), op->getNumOperands()) {} 148 149 //===----------------------------------------------------------------------===// 150 // ResultRange 151 152 ResultRange::ResultRange(Operation *op) 153 : ResultRange(op, /*startIndex=*/0, op->getNumResults()) {} 154 155 /// See `indexed_accessor_range` for details. 156 OpResult ResultRange::dereference(Operation *op, ptrdiff_t index) { 157 return op->getResult(index); 158 } 159 160 //===----------------------------------------------------------------------===// 161 // ValueRange 162 163 ValueRange::ValueRange(ArrayRef<Value> values) 164 : ValueRange(values.data(), values.size()) {} 165 ValueRange::ValueRange(OperandRange values) 166 : ValueRange(values.begin().getBase(), values.size()) {} 167 ValueRange::ValueRange(ResultRange values) 168 : ValueRange( 169 {values.getBase(), static_cast<unsigned>(values.getStartIndex())}, 170 values.size()) {} 171 172 /// See `detail::indexed_accessor_range_base` for details. 173 ValueRange::OwnerT ValueRange::offset_base(const OwnerT &owner, 174 ptrdiff_t index) { 175 if (auto *value = owner.ptr.dyn_cast<const Value *>()) 176 return {value + index}; 177 if (auto *operand = owner.ptr.dyn_cast<OpOperand *>()) 178 return {operand + index}; 179 Operation *operation = reinterpret_cast<Operation *>(owner.ptr.get<void *>()); 180 return {operation, owner.startIndex + static_cast<unsigned>(index)}; 181 } 182 /// See `detail::indexed_accessor_range_base` for details. 183 Value ValueRange::dereference_iterator(const OwnerT &owner, ptrdiff_t index) { 184 if (auto *value = owner.ptr.dyn_cast<const Value *>()) 185 return value[index]; 186 if (auto *operand = owner.ptr.dyn_cast<OpOperand *>()) 187 return operand[index].get(); 188 Operation *operation = reinterpret_cast<Operation *>(owner.ptr.get<void *>()); 189 return operation->getResult(owner.startIndex + index); 190 } 191