diff options
author | Mehdi Amini <aminim@google.com> | 2019-12-24 02:47:41 +0000 |
---|---|---|
committer | Mehdi Amini <aminim@google.com> | 2019-12-24 02:47:41 +0000 |
commit | 0f0d0ed1c78f1a80139a1f2133fad5284691a121 (patch) | |
tree | 31979a3137c364e3eb58e0169a7c4029c7ee7db3 /mlir/lib/IR/Region.cpp | |
parent | 6f635f90929da9545dd696071a829a1a42f84b30 (diff) | |
parent | 5b4a01d4a63cb66ab981e52548f940813393bf42 (diff) | |
download | bcm5719-llvm-0f0d0ed1c78f1a80139a1f2133fad5284691a121.tar.gz bcm5719-llvm-0f0d0ed1c78f1a80139a1f2133fad5284691a121.zip |
Import MLIR into the LLVM tree
Diffstat (limited to 'mlir/lib/IR/Region.cpp')
-rw-r--r-- | mlir/lib/IR/Region.cpp | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/mlir/lib/IR/Region.cpp b/mlir/lib/IR/Region.cpp new file mode 100644 index 00000000000..1e8abc884dd --- /dev/null +++ b/mlir/lib/IR/Region.cpp @@ -0,0 +1,230 @@ +//===- Region.cpp - MLIR Region Class -------------------------------------===// +// +// Part of the MLIR Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "mlir/IR/Region.h" +#include "mlir/IR/BlockAndValueMapping.h" +#include "mlir/IR/Operation.h" +using namespace mlir; + +Region::Region(Operation *container) : container(container) {} + +Region::~Region() { + // Operations may have cyclic references, which need to be dropped before we + // can start deleting them. + dropAllReferences(); +} + +/// Return the context this region is inserted in. The region must have a valid +/// parent container. +MLIRContext *Region::getContext() { + assert(container && "region is not attached to a container"); + return container->getContext(); +} + +/// Return a location for this region. This is the location attached to the +/// parent container. The region must have a valid parent container. +Location Region::getLoc() { + assert(container && "region is not attached to a container"); + return container->getLoc(); +} + +Region *Region::getParentRegion() { + assert(container && "region is not attached to a container"); + return container->getParentRegion(); +} + +Operation *Region::getParentOp() { return container; } + +bool Region::isProperAncestor(Region *other) { + if (this == other) + return false; + + while ((other = other->getParentRegion())) { + if (this == other) + return true; + } + return false; +} + +/// Return the number of this region in the parent operation. +unsigned Region::getRegionNumber() { + // Regions are always stored consecutively, so use pointer subtraction to + // figure out what number this is. + return this - &getParentOp()->getRegions()[0]; +} + +/// Clone the internal blocks from this region into `dest`. Any +/// cloned blocks are appended to the back of dest. +void Region::cloneInto(Region *dest, BlockAndValueMapping &mapper) { + assert(dest && "expected valid region to clone into"); + cloneInto(dest, dest->end(), mapper); +} + +/// Clone this region into 'dest' before the given position in 'dest'. +void Region::cloneInto(Region *dest, Region::iterator destPos, + BlockAndValueMapping &mapper) { + assert(dest && "expected valid region to clone into"); + assert(this != dest && "cannot clone region into itself"); + + // If the list is empty there is nothing to clone. + if (empty()) + return; + + for (Block &block : *this) { + Block *newBlock = new Block(); + mapper.map(&block, newBlock); + + // Clone the block arguments. The user might be deleting arguments to the + // block by specifying them in the mapper. If so, we don't add the + // argument to the cloned block. + for (auto arg : block.getArguments()) + if (!mapper.contains(arg)) + mapper.map(arg, newBlock->addArgument(arg->getType())); + + // Clone and remap the operations within this block. + for (auto &op : block) + newBlock->push_back(op.clone(mapper)); + + dest->getBlocks().insert(destPos, newBlock); + } + + // Now that each of the blocks have been cloned, go through and remap the + // operands of each of the operations. + auto remapOperands = [&](Operation *op) { + for (auto &operand : op->getOpOperands()) + if (auto mappedOp = mapper.lookupOrNull(operand.get())) + operand.set(mappedOp); + for (auto &succOp : op->getBlockOperands()) + if (auto *mappedOp = mapper.lookupOrNull(succOp.get())) + succOp.set(mappedOp); + }; + + for (iterator it(mapper.lookup(&front())); it != destPos; ++it) + it->walk(remapOperands); +} + +void Region::dropAllReferences() { + for (Block &b : *this) + b.dropAllReferences(); +} + +/// Check if there are any values used by operations in `region` defined +/// outside its ancestor region `limit`. That is, given `A{B{C{}}}` with region +/// `C` and limit `B`, the values defined in `B` can be used but the values +/// defined in `A` cannot. Emit errors if `noteLoc` is provided; this location +/// is used to point to the operation containing the region, the actual error is +/// reported at the operation with an offending use. +static bool isIsolatedAbove(Region ®ion, Region &limit, + Optional<Location> noteLoc) { + assert(limit.isAncestor(®ion) && + "expected isolation limit to be an ancestor of the given region"); + + // List of regions to analyze. Each region is processed independently, with + // respect to the common `limit` region, so we can look at them in any order. + // Therefore, use a simple vector and push/pop back the current region. + SmallVector<Region *, 8> pendingRegions; + pendingRegions.push_back(®ion); + + // Traverse all operations in the region. + while (!pendingRegions.empty()) { + for (Block &block : *pendingRegions.pop_back_val()) { + for (Operation &op : block) { + for (Value operand : op.getOperands()) { + // operand should be non-null here if the IR is well-formed. But + // we don't assert here as this function is called from the verifier + // and so could be called on invalid IR. + if (!operand) { + if (noteLoc) + op.emitOpError("block's operand not defined").attachNote(noteLoc); + return false; + } + + // Check that any value that is used by an operation is defined in the + // same region as either an operation result or a block argument. + if (operand->getParentRegion()->isProperAncestor(&limit)) { + if (noteLoc) { + op.emitOpError("using value defined outside the region") + .attachNote(noteLoc) + << "required by region isolation constraints"; + } + return false; + } + } + // Schedule any regions the operations contain for further checking. + pendingRegions.reserve(pendingRegions.size() + op.getNumRegions()); + for (Region &subRegion : op.getRegions()) + pendingRegions.push_back(&subRegion); + } + } + } + return true; +} + +bool Region::isIsolatedFromAbove(Optional<Location> noteLoc) { + return isIsolatedAbove(*this, *this, noteLoc); +} + +Region *llvm::ilist_traits<::mlir::Block>::getParentRegion() { + size_t Offset( + size_t(&((Region *)nullptr->*Region::getSublistAccess(nullptr)))); + iplist<Block> *Anchor(static_cast<iplist<Block> *>(this)); + return reinterpret_cast<Region *>(reinterpret_cast<char *>(Anchor) - Offset); +} + +/// This is a trait method invoked when a basic block is added to a region. +/// We keep the region pointer up to date. +void llvm::ilist_traits<::mlir::Block>::addNodeToList(Block *block) { + assert(!block->getParent() && "already in a region!"); + block->parentValidOpOrderPair.setPointer(getParentRegion()); +} + +/// This is a trait method invoked when an operation is removed from a +/// region. We keep the region pointer up to date. +void llvm::ilist_traits<::mlir::Block>::removeNodeFromList(Block *block) { + assert(block->getParent() && "not already in a region!"); + block->parentValidOpOrderPair.setPointer(nullptr); +} + +/// This is a trait method invoked when an operation is moved from one block +/// to another. We keep the block pointer up to date. +void llvm::ilist_traits<::mlir::Block>::transferNodesFromList( + ilist_traits<Block> &otherList, block_iterator first, block_iterator last) { + // If we are transferring operations within the same function, the parent + // pointer doesn't need to be updated. + auto *curParent = getParentRegion(); + if (curParent == otherList.getParentRegion()) + return; + + // Update the 'parent' member of each Block. + for (; first != last; ++first) + first->parentValidOpOrderPair.setPointer(curParent); +} + +//===----------------------------------------------------------------------===// +// RegionRange +//===----------------------------------------------------------------------===// + +RegionRange::RegionRange(MutableArrayRef<Region> regions) + : RegionRange(regions.data(), regions.size()) {} +RegionRange::RegionRange(ArrayRef<std::unique_ptr<Region>> regions) + : RegionRange(regions.data(), regions.size()) {} + +/// See `detail::indexed_accessor_range_base` for details. +RegionRange::OwnerT RegionRange::offset_base(const OwnerT &owner, + ptrdiff_t index) { + if (auto *operand = owner.dyn_cast<const std::unique_ptr<Region> *>()) + return operand + index; + return &owner.get<Region *>()[index]; +} +/// See `detail::indexed_accessor_range_base` for details. +Region *RegionRange::dereference_iterator(const OwnerT &owner, + ptrdiff_t index) { + if (auto *operand = owner.dyn_cast<const std::unique_ptr<Region> *>()) + return operand[index].get(); + return &owner.get<Region *>()[index]; +} |