summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mlir/include/mlir/IR/Operation.h20
-rw-r--r--mlir/lib/IR/Block.cpp7
-rw-r--r--mlir/lib/IR/Operation.cpp78
3 files changed, 96 insertions, 9 deletions
diff --git a/mlir/include/mlir/IR/Operation.h b/mlir/include/mlir/IR/Operation.h
index 27bc1b17b63..1d9a401cfc0 100644
--- a/mlir/include/mlir/IR/Operation.h
+++ b/mlir/include/mlir/IR/Operation.h
@@ -575,6 +575,26 @@ public:
InFlightDiagnostic emitRemark(const Twine &message = {});
private:
+ //===--------------------------------------------------------------------===//
+ // Ordering
+ //===--------------------------------------------------------------------===//
+
+ /// This value represents an invalid index ordering for an operation within a
+ /// block.
+ static constexpr unsigned kInvalidOrderIdx = -1;
+
+ /// This value represents the stride to use when computing a new order for an
+ /// operation.
+ static constexpr unsigned kOrderStride = 5;
+
+ /// Update the order index of this operation of this operation if necessary,
+ /// potentially recomputing the order of the parent block.
+ void updateOrderIfNecessary();
+
+ /// Returns true if this operation has a valid order.
+ bool hasValidOrder() { return orderIndex != kInvalidOrderIdx; }
+
+private:
Operation(Location location, OperationName name, unsigned numResults,
unsigned numSuccessors, unsigned numRegions,
const NamedAttributeList &attributes);
diff --git a/mlir/lib/IR/Block.cpp b/mlir/lib/IR/Block.cpp
index a5013bd86fb..ad68a36f1ee 100644
--- a/mlir/lib/IR/Block.cpp
+++ b/mlir/lib/IR/Block.cpp
@@ -122,7 +122,8 @@ bool Block::verifyOpOrder() {
for (auto &i : *this) {
// The previous operation must have a smaller order index than the next as
// it appears earlier in the list.
- if (prev && prev->orderIndex >= i.orderIndex)
+ if (prev && prev->orderIndex != Operation::kInvalidOrderIdx &&
+ prev->orderIndex >= i.orderIndex)
return true;
prev = &i;
}
@@ -133,11 +134,9 @@ bool Block::verifyOpOrder() {
void Block::recomputeOpOrder() {
parentValidOpOrderPair.setInt(true);
- // TODO(riverriddle) Have non-congruent indices to reduce the number of times
- // an insert invalidates the list.
unsigned orderIndex = 0;
for (auto &op : *this)
- op.orderIndex = orderIndex++;
+ op.orderIndex = (orderIndex += Operation::kOrderStride);
}
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/IR/Operation.cpp b/mlir/lib/IR/Operation.cpp
index d079033e39b..69b8d056cd5 100644
--- a/mlir/lib/IR/Operation.cpp
+++ b/mlir/lib/IR/Operation.cpp
@@ -366,9 +366,12 @@ InFlightDiagnostic Operation::emitRemark(const Twine &message) {
}
//===----------------------------------------------------------------------===//
-// Other
+// Operation Ordering
//===----------------------------------------------------------------------===//
+constexpr unsigned Operation::kInvalidOrderIdx;
+constexpr unsigned Operation::kOrderStride;
+
/// Given an operation 'other' that is within the same parent block, return
/// whether the current operation is before 'other' in the operation list
/// of the parent block.
@@ -378,12 +381,77 @@ bool Operation::isBeforeInBlock(Operation *other) {
assert(block && "Operations without parent blocks have no order.");
assert(other && other->block == block &&
"Expected other operation to have the same parent block.");
- // Recompute the parent ordering if necessary.
- if (!block->isOpOrderValid())
+ // If the order of the block is already invalid, directly recompute the
+ // parent.
+ if (!block->isOpOrderValid()) {
block->recomputeOpOrder();
+ } else {
+ // Update the order either operation if necessary.
+ updateOrderIfNecessary();
+ other->updateOrderIfNecessary();
+ }
+
return orderIndex < other->orderIndex;
}
+/// Update the order index of this operation of this operation if necessary,
+/// potentially recomputing the order of the parent block.
+void Operation::updateOrderIfNecessary() {
+ assert(block && "expected valid parent");
+
+ // If the order is valid for this operation there is nothing to do.
+ if (hasValidOrder())
+ return;
+ Operation *blockFront = &block->front();
+ Operation *blockBack = &block->back();
+
+ // This method is expected to only be invoked on blocks with more than one
+ // operation.
+ assert(blockFront != blockBack && "expected more than one operation");
+
+ // If the operation is at the end of the block.
+ if (this == blockBack) {
+ Operation *prevNode = getPrevNode();
+ if (!prevNode->hasValidOrder())
+ return block->recomputeOpOrder();
+
+ // Add the stride to the previous operation.
+ orderIndex = prevNode->orderIndex + kOrderStride;
+ return;
+ }
+
+ // If this is the first operation try to use the next operation to compute the
+ // ordering.
+ if (this == blockFront) {
+ Operation *nextNode = getNextNode();
+ if (!nextNode->hasValidOrder())
+ return block->recomputeOpOrder();
+ // There is no order to give this operation.
+ if (nextNode->orderIndex == 0)
+ return block->recomputeOpOrder();
+
+ // If we can't use the stride, just take the middle value left. This is safe
+ // because we know there is at least one valid index to assign to.
+ if (nextNode->orderIndex <= kOrderStride)
+ orderIndex = (nextNode->orderIndex / 2);
+ else
+ orderIndex = kOrderStride;
+ return;
+ }
+
+ // Otherwise, this operation is between two others. Place this operation in
+ // the middle of the previous and next if possible.
+ Operation *prevNode = getPrevNode(), *nextNode = getNextNode();
+ if (!prevNode->hasValidOrder() || !nextNode->hasValidOrder())
+ return block->recomputeOpOrder();
+ unsigned prevOrder = prevNode->orderIndex, nextOrder = nextNode->orderIndex;
+
+ // Check to see if there is a valid order between the two.
+ if (prevOrder + 1 == nextOrder)
+ return block->recomputeOpOrder();
+ orderIndex = prevOrder + 1 + ((nextOrder - prevOrder) / 2);
+}
+
//===----------------------------------------------------------------------===//
// ilist_traits for Operation
//===----------------------------------------------------------------------===//
@@ -430,8 +498,8 @@ void llvm::ilist_traits<::mlir::Operation>::addNodeToList(Operation *op) {
assert(!op->getBlock() && "already in a operation block!");
op->block = getContainingBlock();
- // Invalidate the block ordering.
- op->block->invalidateOpOrder();
+ // Invalidate the order on the operation.
+ op->orderIndex = Operation::kInvalidOrderIdx;
}
/// This is a trait method invoked when a operation is removed from a block.
OpenPOWER on IntegriCloud