Introduce functionality for defining region ancestor relation

Add member functions for Regions to query if another Region is a ancestor.  The
    implementation is naive and traverses all parent regions performing one-to-one
    comparisons.  As a side effect, this introduces `getContainingRegion` function
    for Operations and Values to return the Region in which they are defined, and
    for Regions to return the "parent" region if any.

--

PiperOrigin-RevId: 245057980
This commit is contained in:
Alex Zinenko 2019-04-24 09:24:57 -07:00 committed by Mehdi Amini
parent 9f934f2a59
commit 4beef47b35
8 changed files with 59 additions and 2 deletions

View File

@ -329,7 +329,7 @@ private:
namespace mlir {
/// This class contains a list of basic blocks and has a notion of the object it
/// is part of - a Function or an operation region.
/// is part of - a Function or an Operation.
class Region {
public:
explicit Region(Function *container = nullptr);
@ -360,6 +360,10 @@ public:
return &Region::blocks;
}
/// Return the region containing this region or nullptr if it is a top-level
/// region, i.e. a function body region.
Region *getContainingRegion();
/// A Region is either a function body or a part of an operation. If it is
/// part of an operation, then return the operation, otherwise return null.
Operation *getContainingOp();
@ -368,6 +372,15 @@ public:
/// a Function body, then return this function, otherwise return null.
Function *getContainingFunction();
/// Return true if this region is a proper ancestor of the `other` region.
bool isProperAncestor(Region *other);
/// Return true if this region is ancestor of the `other` region. A region
/// is considered as its own ancestor, use `isProperAncestor` to avoid this.
bool isAncestor(Region *other) {
return this == other || isProperAncestor(other);
}
/// Clone the internal blocks from this region into dest. Any
/// cloned blocks are appended to the back of dest. If the mapper
/// contains entries for block arguments, these arguments are not included

View File

@ -93,7 +93,7 @@ public:
Region &getBody() { return body; }
/// This is the list of blocks in the function.
using RegionType = llvm::iplist<Block>;
using RegionType = Region::RegionType;
RegionType &getBlocks() { return body.getBlocks(); }
// Iteration over the block in the function.

View File

@ -717,6 +717,9 @@ public:
/// Return the operation that this refers to.
Operation *getOperation() { return OpState::getOperation(); }
/// Return the Region enclosing this Op.
Region *getContainingRegion() { return getOperation()->getParentRegion(); }
/// Return true if this "op class" can match against the specified operation.
/// This hook can be overridden with a more specific implementation in
/// the subclass of Base.

View File

@ -113,6 +113,11 @@ public:
/// Set the source location the operation was defined or derived from.
void setLoc(Location loc) { location = loc; }
/// Returns the region to which the instruction belongs, which can be a
/// function body region or a region that belongs to another operation.
/// Returns nullptr if the instruction is unlinked.
Region *getContainingRegion() const;
/// Returns the closest surrounding operation that contains this operation
/// or nullptr if this is a top-level operation.
Operation *getParentOp();

View File

@ -30,6 +30,7 @@ namespace mlir {
class Block;
class Function;
class Operation;
class Region;
class Value;
/// Operands contain a Value.
@ -81,6 +82,9 @@ public:
/// otherwise return an unknown location.
Location getLoc();
/// Return the Region in which this Value is defined.
Region *getContainingRegion();
using use_iterator = ValueUseIterator<OpOperand>;
using use_range = llvm::iterator_range<use_iterator>;

View File

@ -282,6 +282,12 @@ Region::~Region() {
bb.dropAllReferences();
}
Region *Region::getContainingRegion() {
if (auto *inst = getContainingOp())
return inst->getContainingRegion();
return nullptr;
}
Operation *Region::getContainingOp() {
assert(!container.isNull() && "no container");
return container.dyn_cast<Operation *>();
@ -292,6 +298,17 @@ Function *Region::getContainingFunction() {
return container.dyn_cast<Function *>();
}
bool Region::isProperAncestor(Region *other) {
if (this == other)
return false;
while ((other = other->getContainingRegion())) {
if (this == other)
return true;
}
return false;
}
/// 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,

View File

@ -273,6 +273,10 @@ Dialect *Operation::getDialect() {
return getContext()->getRegisteredDialect(dialectPrefix);
}
Region *Operation::getContainingRegion() const {
return block ? block->getParent() : nullptr;
}
Operation *Operation::getParentOp() {
return block ? block->getContainingOp() : nullptr;
}

View File

@ -16,6 +16,7 @@
// =============================================================================
#include "mlir/IR/Value.h"
#include "mlir/IR/Block.h"
#include "mlir/IR/Function.h"
#include "mlir/IR/Operation.h"
using namespace mlir;
@ -45,6 +46,16 @@ Location Value::getLoc() {
return UnknownLoc::get(getContext());
}
/// Return the Region in which this Value is defined.
Region *Value::getContainingRegion() {
switch (getKind()) {
case Value::Kind::BlockArgument:
return cast<BlockArgument>(this)->getOwner()->getParent();
case Value::Kind::OpResult:
return getDefiningOp()->getContainingRegion();
}
}
//===----------------------------------------------------------------------===//
// IRObjectWithUseList implementation.
//===----------------------------------------------------------------------===//