github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/third_party/mlir/lib/IR/Region.cpp (about)

     1  //===- Region.cpp - MLIR Region Class -------------------------------------===//
     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  #include "mlir/IR/Region.h"
    19  #include "mlir/IR/BlockAndValueMapping.h"
    20  #include "mlir/IR/Operation.h"
    21  using namespace mlir;
    22  
    23  Region::Region(Operation *container) : container(container) {}
    24  
    25  Region::~Region() {
    26    // Operations may have cyclic references, which need to be dropped before we
    27    // can start deleting them.
    28    dropAllReferences();
    29  }
    30  
    31  /// Return the context this region is inserted in. The region must have a valid
    32  /// parent container.
    33  MLIRContext *Region::getContext() {
    34    assert(container && "region is not attached to a container");
    35    return container->getContext();
    36  }
    37  
    38  /// Return a location for this region. This is the location attached to the
    39  /// parent container. The region must have a valid parent container.
    40  Location Region::getLoc() {
    41    assert(container && "region is not attached to a container");
    42    return container->getLoc();
    43  }
    44  
    45  Region *Region::getParentRegion() {
    46    assert(container && "region is not attached to a container");
    47    return container->getParentRegion();
    48  }
    49  
    50  Operation *Region::getParentOp() { return container; }
    51  
    52  bool Region::isProperAncestor(Region *other) {
    53    if (this == other)
    54      return false;
    55  
    56    while ((other = other->getParentRegion())) {
    57      if (this == other)
    58        return true;
    59    }
    60    return false;
    61  }
    62  
    63  /// Return the number of this region in the parent operation.
    64  unsigned Region::getRegionNumber() {
    65    // Regions are always stored consecutively, so use pointer subtraction to
    66    // figure out what number this is.
    67    return this - &getParentOp()->getRegions()[0];
    68  }
    69  
    70  /// Clone the internal blocks from this region into `dest`. Any
    71  /// cloned blocks are appended to the back of dest.
    72  void Region::cloneInto(Region *dest, BlockAndValueMapping &mapper) {
    73    assert(dest && "expected valid region to clone into");
    74    cloneInto(dest, dest->end(), mapper);
    75  }
    76  
    77  /// Clone this region into 'dest' before the given position in 'dest'.
    78  void Region::cloneInto(Region *dest, Region::iterator destPos,
    79                         BlockAndValueMapping &mapper) {
    80    assert(dest && "expected valid region to clone into");
    81  
    82    // If the list is empty there is nothing to clone.
    83    if (empty())
    84      return;
    85  
    86    for (Block &block : *this) {
    87      Block *newBlock = new Block();
    88      mapper.map(&block, newBlock);
    89  
    90      // Clone the block arguments. The user might be deleting arguments to the
    91      // block by specifying them in the mapper. If so, we don't add the
    92      // argument to the cloned block.
    93      for (auto *arg : block.getArguments())
    94        if (!mapper.contains(arg))
    95          mapper.map(arg, newBlock->addArgument(arg->getType()));
    96  
    97      // Clone and remap the operations within this block.
    98      for (auto &op : block)
    99        newBlock->push_back(op.clone(mapper));
   100  
   101      dest->getBlocks().insert(destPos, newBlock);
   102    }
   103  
   104    // Now that each of the blocks have been cloned, go through and remap the
   105    // operands of each of the operations.
   106    auto remapOperands = [&](Operation *op) {
   107      for (auto &operand : op->getOpOperands())
   108        if (auto *mappedOp = mapper.lookupOrNull(operand.get()))
   109          operand.set(mappedOp);
   110      for (auto &succOp : op->getBlockOperands())
   111        if (auto *mappedOp = mapper.lookupOrNull(succOp.get()))
   112          succOp.set(mappedOp);
   113    };
   114  
   115    for (iterator it(mapper.lookup(&front())); it != destPos; ++it)
   116      it->walk(remapOperands);
   117  }
   118  
   119  void Region::dropAllReferences() {
   120    for (Block &b : *this)
   121      b.dropAllReferences();
   122  }
   123  
   124  /// Check if there are any values used by operations in `region` defined
   125  /// outside its ancestor region `limit`.  That is, given `A{B{C{}}}` with region
   126  /// `C` and limit `B`, the values defined in `B` can be used but the values
   127  /// defined in `A` cannot.  Emit errors if `noteLoc` is provided; this location
   128  /// is used to point to the operation containing the region, the actual error is
   129  /// reported at the operation with an offending use.
   130  static bool isIsolatedAbove(Region &region, Region &limit,
   131                              llvm::Optional<Location> noteLoc) {
   132    assert(limit.isAncestor(&region) &&
   133           "expected isolation limit to be an ancestor of the given region");
   134  
   135    // List of regions to analyze.  Each region is processed independently, with
   136    // respect to the common `limit` region, so we can look at them in any order.
   137    // Therefore, use a simple vector and push/pop back the current region.
   138    SmallVector<Region *, 8> pendingRegions;
   139    pendingRegions.push_back(&region);
   140  
   141    // Traverse all operations in the region.
   142    while (!pendingRegions.empty()) {
   143      for (Block &block : *pendingRegions.pop_back_val()) {
   144        for (Operation &op : block) {
   145          for (Value *operand : op.getOperands()) {
   146            // Check that any value that is used by an operation is defined in the
   147            // same region as either an operation result or a block argument.
   148            if (operand->getParentRegion()->isProperAncestor(&limit)) {
   149              if (noteLoc) {
   150                op.emitOpError("using value defined outside the region")
   151                        .attachNote(noteLoc)
   152                    << "required by region isolation constraints";
   153              }
   154              return false;
   155            }
   156          }
   157          // Schedule any regions the operations contain for further checking.
   158          pendingRegions.reserve(pendingRegions.size() + op.getNumRegions());
   159          for (Region &subRegion : op.getRegions())
   160            pendingRegions.push_back(&subRegion);
   161        }
   162      }
   163    }
   164    return true;
   165  }
   166  
   167  bool Region::isIsolatedFromAbove(llvm::Optional<Location> noteLoc) {
   168    return isIsolatedAbove(*this, *this, noteLoc);
   169  }
   170  
   171  Region *llvm::ilist_traits<::mlir::Block>::getParentRegion() {
   172    size_t Offset(
   173        size_t(&((Region *)nullptr->*Region::getSublistAccess(nullptr))));
   174    iplist<Block> *Anchor(static_cast<iplist<Block> *>(this));
   175    return reinterpret_cast<Region *>(reinterpret_cast<char *>(Anchor) - Offset);
   176  }
   177  
   178  /// This is a trait method invoked when a basic block is added to a region.
   179  /// We keep the region pointer up to date.
   180  void llvm::ilist_traits<::mlir::Block>::addNodeToList(Block *block) {
   181    assert(!block->getParent() && "already in a region!");
   182    block->parentValidInstOrderPair.setPointer(getParentRegion());
   183  }
   184  
   185  /// This is a trait method invoked when an operation is removed from a
   186  /// region.  We keep the region pointer up to date.
   187  void llvm::ilist_traits<::mlir::Block>::removeNodeFromList(Block *block) {
   188    assert(block->getParent() && "not already in a region!");
   189    block->parentValidInstOrderPair.setPointer(nullptr);
   190  }
   191  
   192  /// This is a trait method invoked when an operation is moved from one block
   193  /// to another.  We keep the block pointer up to date.
   194  void llvm::ilist_traits<::mlir::Block>::transferNodesFromList(
   195      ilist_traits<Block> &otherList, block_iterator first, block_iterator last) {
   196    // If we are transferring operations within the same function, the parent
   197    // pointer doesn't need to be updated.
   198    auto *curParent = getParentRegion();
   199    if (curParent == otherList.getParentRegion())
   200      return;
   201  
   202    // Update the 'parent' member of each Block.
   203    for (; first != last; ++first)
   204      first->parentValidInstOrderPair.setPointer(curParent);
   205  }