summaryrefslogtreecommitdiffstats
path: root/mlir/lib/IR
diff options
context:
space:
mode:
authorRiver Riddle <riverriddle@google.com>2019-12-04 16:09:41 -0800
committerA. Unique TensorFlower <gardener@tensorflow.org>2019-12-04 16:10:13 -0800
commitd9da8b647a5a416941c6e1566c29f3a0eda3d503 (patch)
tree4e0a22eee65ac80002f757786dc267074373eb75 /mlir/lib/IR
parent2c930f8d9daa04576ac49e14c19dc540ebf823fe (diff)
downloadbcm5719-llvm-d9da8b647a5a416941c6e1566c29f3a0eda3d503.tar.gz
bcm5719-llvm-d9da8b647a5a416941c6e1566c29f3a0eda3d503.zip
Optimize operation ordering to support non-congruent indices.
This change adds support for non-congruent indices in the operation ordering within a basic block. This effect of this is that insertions are less likely to cause an invalidation of the ordering within a block. This has a big effect on modules that have very large basic blocks. PiperOrigin-RevId: 283858136
Diffstat (limited to 'mlir/lib/IR')
-rw-r--r--mlir/lib/IR/Block.cpp7
-rw-r--r--mlir/lib/IR/Operation.cpp78
2 files changed, 76 insertions, 9 deletions
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