1 //===- OperationSupport.cpp -----------------------------------------------===// 2 // 3 // Copyright 2019 The MLIR Authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 // ============================================================================= 17 // 18 // This file contains out-of-line implementations of the support types that 19 // Operation and related classes build on top of. 20 // 21 //===----------------------------------------------------------------------===// 22 23 #include "mlir/IR/OperationSupport.h" 24 #include "mlir/IR/Block.h" 25 #include "mlir/IR/Operation.h" 26 using namespace mlir; 27 28 //===----------------------------------------------------------------------===// 29 // OperationState 30 //===----------------------------------------------------------------------===// 31 32 OperationState::OperationState(Location location, StringRef name) 33 : location(location), name(name, location->getContext()) {} 34 35 OperationState::OperationState(Location location, OperationName name) 36 : location(location), name(name) {} 37 38 OperationState::OperationState(Location location, StringRef name, 39 ValueRange operands, ArrayRef<Type> types, 40 ArrayRef<NamedAttribute> attributes, 41 ArrayRef<Block *> successors, 42 MutableArrayRef<std::unique_ptr<Region>> regions, 43 bool resizableOperandList) 44 : location(location), name(name, location->getContext()), 45 operands(operands.begin(), operands.end()), 46 types(types.begin(), types.end()), 47 attributes(attributes.begin(), attributes.end()), 48 successors(successors.begin(), successors.end()) { 49 for (std::unique_ptr<Region> &r : regions) 50 this->regions.push_back(std::move(r)); 51 } 52 53 void OperationState::addOperands(ValueRange newOperands) { 54 assert(successors.empty() && "Non successor operands should be added first."); 55 operands.append(newOperands.begin(), newOperands.end()); 56 } 57 58 void OperationState::addSuccessor(Block *successor, ValueRange succOperands) { 59 successors.push_back(successor); 60 // Insert a sentinel operand to mark a barrier between successor operands. 61 operands.push_back(nullptr); 62 operands.append(succOperands.begin(), succOperands.end()); 63 } 64 65 Region *OperationState::addRegion() { 66 regions.emplace_back(new Region); 67 return regions.back().get(); 68 } 69 70 void OperationState::addRegion(std::unique_ptr<Region> &®ion) { 71 regions.push_back(std::move(region)); 72 } 73 74 //===----------------------------------------------------------------------===// 75 // OperandStorage 76 //===----------------------------------------------------------------------===// 77 78 /// Replace the operands contained in the storage with the ones provided in 79 /// 'operands'. 80 void detail::OperandStorage::setOperands(Operation *owner, 81 ValueRange operands) { 82 // If the number of operands is less than or equal to the current amount, we 83 // can just update in place. 84 if (operands.size() <= numOperands) { 85 auto opOperands = getOperands(); 86 87 // If the number of new operands is less than the current count, then remove 88 // any extra operands. 89 for (unsigned i = operands.size(); i != numOperands; ++i) 90 opOperands[i].~OpOperand(); 91 92 // Set the operands in place. 93 numOperands = operands.size(); 94 for (unsigned i = 0; i != numOperands; ++i) 95 opOperands[i].set(operands[i]); 96 return; 97 } 98 99 // Otherwise, we need to be resizable. 100 assert(resizable && "Only resizable operations may add operands"); 101 102 // Grow the capacity if necessary. 103 auto &resizeUtil = getResizableStorage(); 104 if (resizeUtil.capacity < operands.size()) 105 grow(resizeUtil, operands.size()); 106 107 // Set the operands. 108 OpOperand *opBegin = getRawOperands(); 109 for (unsigned i = 0; i != numOperands; ++i) 110 opBegin[i].set(operands[i]); 111 for (unsigned e = operands.size(); numOperands != e; ++numOperands) 112 new (&opBegin[numOperands]) OpOperand(owner, operands[numOperands]); 113 } 114 115 /// Erase an operand held by the storage. 116 void detail::OperandStorage::eraseOperand(unsigned index) { 117 assert(index < size()); 118 auto operands = getOperands(); 119 --numOperands; 120 121 // Shift all operands down by 1 if the operand to remove is not at the end. 122 auto indexIt = std::next(operands.begin(), index); 123 if (index != numOperands) 124 std::rotate(indexIt, std::next(indexIt), operands.end()); 125 operands[numOperands].~OpOperand(); 126 } 127 128 /// Grow the internal operand storage. 129 void detail::OperandStorage::grow(ResizableStorage &resizeUtil, 130 size_t minSize) { 131 // Allocate a new storage array. 132 resizeUtil.capacity = 133 std::max(size_t(llvm::NextPowerOf2(resizeUtil.capacity + 2)), minSize); 134 OpOperand *newStorage = static_cast<OpOperand *>( 135 llvm::safe_malloc(resizeUtil.capacity * sizeof(OpOperand))); 136 137 // Move the current operands to the new storage. 138 auto operands = getOperands(); 139 std::uninitialized_copy(std::make_move_iterator(operands.begin()), 140 std::make_move_iterator(operands.end()), newStorage); 141 142 // Destroy the original operands and update the resizable storage pointer. 143 for (auto &operand : operands) 144 operand.~OpOperand(); 145 resizeUtil.setDynamicStorage(newStorage); 146 } 147 148 //===----------------------------------------------------------------------===// 149 // Operation Value-Iterators 150 //===----------------------------------------------------------------------===// 151 152 //===----------------------------------------------------------------------===// 153 // OperandRange 154 155 OperandRange::OperandRange(Operation *op) 156 : OperandRange(op->getOpOperands().data(), op->getNumOperands()) {} 157 158 //===----------------------------------------------------------------------===// 159 // ResultRange 160 161 ResultRange::ResultRange(Operation *op) 162 : ResultRange(op->getOpResults().data(), op->getNumResults()) {} 163 164 //===----------------------------------------------------------------------===// 165 // ValueRange 166 167 ValueRange::ValueRange(ArrayRef<Value *> values) 168 : ValueRange(values.data(), values.size()) {} 169 ValueRange::ValueRange(OperandRange values) 170 : ValueRange(values.begin().getBase(), values.size()) {} 171 ValueRange::ValueRange(ResultRange values) 172 : ValueRange(values.begin().getBase(), values.size()) {} 173 174 /// See `detail::indexed_accessor_range_base` for details. 175 ValueRange::OwnerT ValueRange::offset_base(const OwnerT &owner, 176 ptrdiff_t index) { 177 if (OpOperand *operand = owner.dyn_cast<OpOperand *>()) 178 return operand + index; 179 if (OpResult *result = owner.dyn_cast<OpResult *>()) 180 return result + index; 181 return owner.get<Value *const *>() + index; 182 } 183 /// See `detail::indexed_accessor_range_base` for details. 184 Value *ValueRange::dereference_iterator(const OwnerT &owner, ptrdiff_t index) { 185 // Operands access the held value via 'get'. 186 if (OpOperand *operand = owner.dyn_cast<OpOperand *>()) 187 return operand[index].get(); 188 // An OpResult is a value, so we can return it directly. 189 if (OpResult *result = owner.dyn_cast<OpResult *>()) 190 return &result[index]; 191 // Otherwise, this is a raw value array so just index directly. 192 return owner.get<Value *const *>()[index]; 193 } 194