diff options
| author | River Riddle <riverriddle@google.com> | 2019-12-04 16:09:41 -0800 |
|---|---|---|
| committer | A. Unique TensorFlower <gardener@tensorflow.org> | 2019-12-04 16:10:13 -0800 |
| commit | d9da8b647a5a416941c6e1566c29f3a0eda3d503 (patch) | |
| tree | 4e0a22eee65ac80002f757786dc267074373eb75 /mlir/lib/IR | |
| parent | 2c930f8d9daa04576ac49e14c19dc540ebf823fe (diff) | |
| download | bcm5719-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.cpp | 7 | ||||
| -rw-r--r-- | mlir/lib/IR/Operation.cpp | 78 |
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. |

