| //===- OperationSupport.cpp -----------------------------------------------===// |
| // |
| // Copyright 2019 The MLIR Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // ============================================================================= |
| // |
| // This file contains out-of-line implementations of the support types that |
| // Operation and related classes build on top of. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "mlir/IR/OperationSupport.h" |
| #include "mlir/IR/Block.h" |
| #include "mlir/IR/Operation.h" |
| using namespace mlir; |
| |
| //===----------------------------------------------------------------------===// |
| // OperationState |
| //===----------------------------------------------------------------------===// |
| |
| OperationState::OperationState(Location location, StringRef name) |
| : context(location->getContext()), location(location), |
| name(name, location->getContext()) {} |
| |
| OperationState::OperationState(Location location, OperationName name) |
| : context(location->getContext()), location(location), name(name) {} |
| |
| OperationState::OperationState(Location location, StringRef name, |
| ArrayRef<Value *> operands, ArrayRef<Type> types, |
| ArrayRef<NamedAttribute> attributes, |
| ArrayRef<Block *> successors, |
| MutableArrayRef<std::unique_ptr<Region>> regions, |
| bool resizableOperandList) |
| : context(location->getContext()), location(location), |
| name(name, location->getContext()), |
| operands(operands.begin(), operands.end()), |
| types(types.begin(), types.end()), |
| attributes(attributes.begin(), attributes.end()), |
| successors(successors.begin(), successors.end()) { |
| for (std::unique_ptr<Region> &r : regions) { |
| this->regions.push_back(std::move(r)); |
| } |
| } |
| |
| Region *OperationState::addRegion() { |
| regions.emplace_back(new Region); |
| return regions.back().get(); |
| } |
| |
| void OperationState::addRegion(std::unique_ptr<Region> &®ion) { |
| regions.push_back(std::move(region)); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // OperandStorage |
| //===----------------------------------------------------------------------===// |
| |
| /// Replace the operands contained in the storage with the ones provided in |
| /// 'operands'. |
| void detail::OperandStorage::setOperands(Operation *owner, |
| ArrayRef<Value *> operands) { |
| // If the number of operands is less than or equal to the current amount, we |
| // can just update in place. |
| if (operands.size() <= numOperands) { |
| auto opOperands = getOperands(); |
| |
| // If the number of new operands is less than the current count, then remove |
| // any extra operands. |
| for (unsigned i = operands.size(); i != numOperands; ++i) |
| opOperands[i].~OpOperand(); |
| |
| // Set the operands in place. |
| numOperands = operands.size(); |
| for (unsigned i = 0; i != numOperands; ++i) |
| opOperands[i].set(operands[i]); |
| return; |
| } |
| |
| // Otherwise, we need to be resizable. |
| assert(resizable && "Only resizable operations may add operands"); |
| |
| // Grow the capacity if necessary. |
| auto &resizeUtil = getResizableStorage(); |
| if (resizeUtil.capacity < operands.size()) |
| grow(resizeUtil, operands.size()); |
| |
| // Set the operands. |
| OpOperand *opBegin = getRawOperands(); |
| for (unsigned i = 0; i != numOperands; ++i) |
| opBegin[i].set(operands[i]); |
| for (unsigned e = operands.size(); numOperands != e; ++numOperands) |
| new (&opBegin[numOperands]) OpOperand(owner, operands[numOperands]); |
| } |
| |
| /// Erase an operand held by the storage. |
| void detail::OperandStorage::eraseOperand(unsigned index) { |
| assert(index < size()); |
| auto operands = getOperands(); |
| --numOperands; |
| |
| // Shift all operands down by 1 if the operand to remove is not at the end. |
| auto indexIt = std::next(operands.begin(), index); |
| if (index != numOperands) |
| std::rotate(indexIt, std::next(indexIt), operands.end()); |
| operands[numOperands].~OpOperand(); |
| } |
| |
| /// Grow the internal operand storage. |
| void detail::OperandStorage::grow(ResizableStorage &resizeUtil, |
| size_t minSize) { |
| // Allocate a new storage array. |
| resizeUtil.capacity = |
| std::max(size_t(llvm::NextPowerOf2(resizeUtil.capacity + 2)), minSize); |
| OpOperand *newStorage = static_cast<OpOperand *>( |
| llvm::safe_malloc(resizeUtil.capacity * sizeof(OpOperand))); |
| |
| // Move the current operands to the new storage. |
| auto operands = getOperands(); |
| std::uninitialized_copy(std::make_move_iterator(operands.begin()), |
| std::make_move_iterator(operands.end()), newStorage); |
| |
| // Destroy the original operands and update the resizable storage pointer. |
| for (auto &operand : operands) |
| operand.~OpOperand(); |
| resizeUtil.setDynamicStorage(newStorage); |
| } |