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> &®ion) { 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