-
Notifications
You must be signed in to change notification settings - Fork 14.8k
[mlir][IR] Adjust insertion block when splitting blocks / moving ops #150819
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -576,24 +576,39 @@ class RewriterBase : public OpBuilder { | |||||||||
|
||||||||||
/// Split the operations starting at "before" (inclusive) out of the given | ||||||||||
/// block into a new block, and return it. | ||||||||||
/// | ||||||||||
/// If the current insertion point is before the split point, the insertion | ||||||||||
/// point is adjusted to the new block. | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this could be made clearer in that the insertion point is set to the exact same location in the new block.
Suggested change
|
||||||||||
Block *splitBlock(Block *block, Block::iterator before); | ||||||||||
|
||||||||||
/// Unlink this operation from its current block and insert it right before | ||||||||||
/// `existingOp` which may be in the same or another block in the same | ||||||||||
/// function. | ||||||||||
/// | ||||||||||
/// If the insertion point is before the moved operation, the insertion block | ||||||||||
/// is adjusted to the block of `existingOp`. | ||||||||||
void moveOpBefore(Operation *op, Operation *existingOp); | ||||||||||
|
||||||||||
/// Unlink this operation from its current block and insert it right before | ||||||||||
/// `iterator` in the specified block. | ||||||||||
/// | ||||||||||
/// If the insertion point is before the moved operation, the insertion block | ||||||||||
/// is adjusted to the specified block. | ||||||||||
void moveOpBefore(Operation *op, Block *block, Block::iterator iterator); | ||||||||||
|
||||||||||
/// Unlink this operation from its current block and insert it right after | ||||||||||
/// `existingOp` which may be in the same or another block in the same | ||||||||||
/// function. | ||||||||||
/// | ||||||||||
/// If the insertion point is before the moved operation, the insertion block | ||||||||||
/// is adjusted to the block of `existingOp`. | ||||||||||
void moveOpAfter(Operation *op, Operation *existingOp); | ||||||||||
|
||||||||||
/// Unlink this operation from its current block and insert it right after | ||||||||||
/// `iterator` in the specified block. | ||||||||||
/// | ||||||||||
/// If the insertion point is before the moved operation, the insertion block | ||||||||||
/// is adjusted to the specified block. | ||||||||||
Comment on lines
+587
to
+611
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not fully confident this is the best behaviour for these operations but I fear this depends on ones iternal model of the insertion point. In my mind, erasing an operation and moving an operation from the POV of the current insertion point are not much different: In both cases the erased/moved op disappears from the current insertion point and arguably the insertion point shouldn't care what happens to it after. My expected behaviour would then be similar to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, it is a bit odd that the insertion point "jumps", potentially even into a different block. |
||||||||||
void moveOpAfter(Operation *op, Block *block, Block::iterator iterator); | ||||||||||
|
||||||||||
/// Unlink this block and insert it right before `existingBlock`. | ||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -68,6 +68,16 @@ void Block::erase() { | |
getParent()->getBlocks().erase(this); | ||
} | ||
|
||
bool Block::isBeforeInBlock(iterator a, iterator b) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add an assertion that they are in the same block here? |
||
if (a == b) | ||
return false; | ||
if (a == end()) | ||
return false; | ||
if (b == end()) | ||
return true; | ||
return a->isBeforeInBlock(&*b); | ||
} | ||
|
||
/// Returns 'op' if 'op' lies in this block, or otherwise finds the | ||
/// ancestor operation of 'op' that lies in this block. Returns nullptr if | ||
/// the latter fails. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ | |
#include "mlir/IR/PatternMatch.h" | ||
#include "mlir/IR/Iterators.h" | ||
#include "mlir/IR/RegionKindInterface.h" | ||
#include "llvm/ADT/ScopeExit.h" | ||
#include "llvm/ADT/SmallPtrSet.h" | ||
|
||
using namespace mlir; | ||
|
@@ -348,14 +349,29 @@ void RewriterBase::mergeBlocks(Block *source, Block *dest, | |
/// Split the operations starting at "before" (inclusive) out of the given | ||
/// block into a new block, and return it. | ||
Block *RewriterBase::splitBlock(Block *block, Block::iterator before) { | ||
Block *newBlock; | ||
|
||
// If the current insertion point is at or after the split point, adjust the | ||
// insertion point to the new block. | ||
bool moveIpToNewBlock = getBlock() == block && | ||
!block->isBeforeInBlock(getInsertionPoint(), before); | ||
auto adjustInsertionPoint = llvm::make_scope_exit([&]() { | ||
if (getInsertionPoint() == block->end()) { | ||
// If the insertion point is at the end of the block, move it to the end | ||
// of the new block. | ||
setInsertionPointToEnd(newBlock); | ||
} else if (moveIpToNewBlock) { | ||
setInsertionPoint(newBlock, getInsertionPoint()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using Copilot generated this review using guidance from copilot-instructions.md. Positive FeedbackNegative Feedback |
||
} | ||
}); | ||
Comment on lines
+354
to
+366
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there an easy way we can test the logic here? |
||
|
||
// Fast path: If no listener is attached, split the block directly. | ||
if (!listener) | ||
return block->splitBlock(before); | ||
return newBlock = block->splitBlock(before); | ||
|
||
Comment on lines
369
to
371
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nitpick] The assignment within the return statement makes the code harder to read. Consider separating the assignment from the return statement for clarity. Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||
// `createBlock` sets the insertion point at the beginning of the new block. | ||
InsertionGuard g(*this); | ||
Block *newBlock = | ||
createBlock(block->getParent(), std::next(block->getIterator())); | ||
newBlock = createBlock(block->getParent(), std::next(block->getIterator())); | ||
|
||
// If `before` points to end of the block, no ops should be moved. | ||
if (before == block->end()) | ||
|
@@ -413,6 +429,12 @@ void RewriterBase::moveOpBefore(Operation *op, Block *block, | |
Block *currentBlock = op->getBlock(); | ||
Block::iterator nextIterator = std::next(op->getIterator()); | ||
op->moveBefore(block, iterator); | ||
|
||
// If the current insertion point is before the moved operation, we may have | ||
// to adjust the insertion block. | ||
if (getInsertionPoint() == op->getIterator()) | ||
setInsertionPoint(block, op->getIterator()); | ||
|
||
if (listener) | ||
listener->notifyOperationInserted( | ||
op, /*previous=*/InsertPoint(currentBlock, nextIterator)); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.