brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.9 KiB · 15a941f Raw
300 lines · cpp
1//===- Region.cpp - MLIR Region Class -------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "mlir/IR/Region.h"10#include "mlir/IR/IRMapping.h"11#include "mlir/IR/Operation.h"12using namespace mlir;13 14Region::Region(Operation *container) : container(container) {}15 16Region::~Region() {17  // Operations may have cyclic references, which need to be dropped before we18  // can start deleting them.19  dropAllReferences();20}21 22/// Return the context this region is inserted in. The region must have a valid23/// parent container.24MLIRContext *Region::getContext() {25  assert(container && "region is not attached to a container");26  return container->getContext();27}28 29/// Return a location for this region. This is the location attached to the30/// parent container. The region must have a valid parent container.31Location Region::getLoc() {32  assert(container && "region is not attached to a container");33  return container->getLoc();34}35 36auto Region::getArgumentTypes() -> ValueTypeRange<BlockArgListType> {37  return ValueTypeRange<BlockArgListType>(getArguments());38}39 40iterator_range<Region::args_iterator>41Region::addArguments(TypeRange types, ArrayRef<Location> locs) {42  return front().addArguments(types, locs);43}44 45Region *Region::getParentRegion() {46  assert(container && "region is not attached to a container");47  return container->getParentRegion();48}49 50bool Region::isProperAncestor(Region *other) {51  if (this == other)52    return false;53 54  while ((other = other->getParentRegion())) {55    if (this == other)56      return true;57  }58  return false;59}60 61/// Return the number of this region in the parent operation.62unsigned Region::getRegionNumber() {63  // Regions are always stored consecutively, so use pointer subtraction to64  // figure out what number this is.65  return this - &getParentOp()->getRegions()[0];66}67 68/// Clone the internal blocks from this region into `dest`. Any69/// cloned blocks are appended to the back of dest.70void Region::cloneInto(Region *dest, IRMapping &mapper) {71  assert(dest && "expected valid region to clone into");72  cloneInto(dest, dest->end(), mapper);73}74 75/// Clone this region into 'dest' before the given position in 'dest'.76void Region::cloneInto(Region *dest, Region::iterator destPos,77                       IRMapping &mapper) {78  assert(dest && "expected valid region to clone into");79  assert(this != dest && "cannot clone region into itself");80 81  // If the list is empty there is nothing to clone.82  if (empty())83    return;84 85  // The below clone implementation takes special care to be read only for the86  // sake of multi threading. That essentially means not adding any uses to any87  // of the blocks or operation results contained within this region as that88  // would lead to a write in their use-def list. This is unavoidable for89  // 'Value's from outside the region however, in which case it is not read90  // only. Using the IRMapper it is possible to remap such 'Value's91  // to ones owned by the calling thread however, making it read only once92  // again.93 94  // First clone all the blocks and block arguments and map them, but don't yet95  // clone the operations, as they may otherwise add a use to a block that has96  // not yet been mapped97  for (Block &block : *this) {98    Block *newBlock = new Block();99    mapper.map(&block, newBlock);100 101    // Clone the block arguments. The user might be deleting arguments to the102    // block by specifying them in the mapper. If so, we don't add the103    // argument to the cloned block.104    for (auto arg : block.getArguments())105      if (!mapper.contains(arg))106        mapper.map(arg, newBlock->addArgument(arg.getType(), arg.getLoc()));107 108    dest->getBlocks().insert(destPos, newBlock);109  }110 111  auto newBlocksRange =112      llvm::make_range(Region::iterator(mapper.lookup(&front())), destPos);113 114  // Now follow up with creating the operations, but don't yet clone their115  // regions, nor set their operands. Setting the successors is safe as all have116  // already been mapped. We are essentially just creating the operation results117  // to be able to map them.118  // Cloning the operands and region as well would lead to uses of operations119  // not yet mapped.120  auto cloneOptions =121      Operation::CloneOptions::all().cloneRegions(false).cloneOperands(false);122  for (auto zippedBlocks : llvm::zip(*this, newBlocksRange)) {123    Block &sourceBlock = std::get<0>(zippedBlocks);124    Block &clonedBlock = std::get<1>(zippedBlocks);125    // Clone and remap the operations within this block.126    for (Operation &op : sourceBlock)127      clonedBlock.push_back(op.clone(mapper, cloneOptions));128  }129 130  // Finally now that all operation results have been mapped, set the operands131  // and clone the regions.132  SmallVector<Value> operands;133  for (auto zippedBlocks : llvm::zip(*this, newBlocksRange)) {134    for (auto ops :135         llvm::zip(std::get<0>(zippedBlocks), std::get<1>(zippedBlocks))) {136      Operation &source = std::get<0>(ops);137      Operation &clone = std::get<1>(ops);138 139      operands.resize(source.getNumOperands());140      llvm::transform(141          source.getOperands(), operands.begin(),142          [&](Value operand) { return mapper.lookupOrDefault(operand); });143      clone.setOperands(operands);144 145      for (auto regions : llvm::zip(source.getRegions(), clone.getRegions()))146        std::get<0>(regions).cloneInto(&std::get<1>(regions), mapper);147    }148  }149}150 151/// Returns 'block' if 'block' lies in this region, or otherwise finds the152/// ancestor of 'block' that lies in this region. Returns nullptr if the latter153/// fails.154Block *Region::findAncestorBlockInRegion(Block &block) {155  Block *currBlock = &block;156  while (currBlock->getParent() != this) {157    Operation *parentOp = currBlock->getParentOp();158    if (!parentOp || !parentOp->getBlock())159      return nullptr;160    currBlock = parentOp->getBlock();161  }162  return currBlock;163}164 165/// Returns 'op' if 'op' lies in this region, or otherwise finds the166/// ancestor of 'op' that lies in this region. Returns nullptr if the167/// latter fails.168Operation *Region::findAncestorOpInRegion(Operation &op) {169  Operation *curOp = &op;170  while (Region *opRegion = curOp->getParentRegion()) {171    if (opRegion == this)172      return curOp;173 174    curOp = opRegion->getParentOp();175    if (!curOp)176      return nullptr;177  }178  return nullptr;179}180 181void Region::dropAllReferences() {182  for (Block &b : *this)183    b.dropAllReferences();184}185 186Region *llvm::ilist_traits<::mlir::Block>::getParentRegion() {187  size_t offset(188      size_t(&((Region *)nullptr->*Region::getSublistAccess(nullptr))));189  iplist<Block> *anchor(static_cast<iplist<Block> *>(this));190  return reinterpret_cast<Region *>(reinterpret_cast<char *>(anchor) - offset);191}192 193/// This is a trait method invoked when a basic block is added to a region.194/// We keep the region pointer up to date.195void llvm::ilist_traits<::mlir::Block>::addNodeToList(Block *block) {196  assert(!block->getParent() && "already in a region!");197  block->parentValidOpOrderPair.setPointer(getParentRegion());198}199 200/// This is a trait method invoked when an operation is removed from a201/// region.  We keep the region pointer up to date.202void llvm::ilist_traits<::mlir::Block>::removeNodeFromList(Block *block) {203  assert(block->getParent() && "not already in a region!");204  block->parentValidOpOrderPair.setPointer(nullptr);205}206 207/// This is a trait method invoked when an operation is moved from one block208/// to another.  We keep the block pointer up to date.209void llvm::ilist_traits<::mlir::Block>::transferNodesFromList(210    ilist_traits<Block> &otherList, block_iterator first, block_iterator last) {211  // If we are transferring operations within the same function, the parent212  // pointer doesn't need to be updated.213  auto *curParent = getParentRegion();214  if (curParent == otherList.getParentRegion())215    return;216 217  // Update the 'parent' member of each Block.218  for (; first != last; ++first)219    first->parentValidOpOrderPair.setPointer(curParent);220}221 222//===----------------------------------------------------------------------===//223// Region::OpIterator224//===----------------------------------------------------------------------===//225 226Region::OpIterator::OpIterator(Region *region, bool end)227    : region(region), block(end ? region->end() : region->begin()) {228  if (!region->empty())229    skipOverBlocksWithNoOps();230}231 232Region::OpIterator &Region::OpIterator::operator++() {233  // We increment over operations, if we reach the last use then move to next234  // block.235  if (operation != block->end())236    ++operation;237  if (operation == block->end()) {238    ++block;239    skipOverBlocksWithNoOps();240  }241  return *this;242}243 244void Region::OpIterator::skipOverBlocksWithNoOps() {245  while (block != region->end() && block->empty())246    ++block;247 248  // If we are at the last block, then set the operation to first operation of249  // next block (sentinel value used for end).250  if (block == region->end())251    operation = {};252  else253    operation = block->begin();254}255 256llvm::raw_ostream &mlir::operator<<(llvm::raw_ostream &os, Region &region) {257  if (!region.getParentOp()) {258    os << "Region has no parent op";259  } else {260    os << "Region #" << region.getRegionNumber() << " in operation "261       << region.getParentOp()->getName();262  }263  for (auto it : llvm::enumerate(region.getBlocks())) {264    os << "\n  Block #" << it.index() << ":";265    for (Operation &op : it.value().getOperations())266      os << "\n    " << OpWithFlags(&op, OpPrintingFlags().skipRegions());267  }268  return os;269}270 271//===----------------------------------------------------------------------===//272// RegionRange273//===----------------------------------------------------------------------===//274 275RegionRange::RegionRange(MutableArrayRef<Region> regions)276    : RegionRange(regions.data(), regions.size()) {}277RegionRange::RegionRange(ArrayRef<std::unique_ptr<Region>> regions)278    : RegionRange(regions.data(), regions.size()) {}279RegionRange::RegionRange(ArrayRef<Region *> regions)280    : RegionRange(const_cast<Region **>(regions.data()), regions.size()) {}281 282/// See `llvm::detail::indexed_accessor_range_base` for details.283RegionRange::OwnerT RegionRange::offset_base(const OwnerT &owner,284                                             ptrdiff_t index) {285  if (auto *region = llvm::dyn_cast_if_present<const std::unique_ptr<Region> *>(owner))286    return region + index;287  if (auto **region = llvm::dyn_cast_if_present<Region **>(owner))288    return region + index;289  return &cast<Region *>(owner)[index];290}291/// See `llvm::detail::indexed_accessor_range_base` for details.292Region *RegionRange::dereference_iterator(const OwnerT &owner,293                                          ptrdiff_t index) {294  if (auto *region = llvm::dyn_cast_if_present<const std::unique_ptr<Region> *>(owner))295    return region[index].get();296  if (auto **region = llvm::dyn_cast_if_present<Region **>(owner))297    return region[index];298  return &cast<Region *>(owner)[index];299}300