-
Notifications
You must be signed in to change notification settings - Fork 207
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
Add WriteAfterWriteElimination pass #2572
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: Anna Gringauze <agringauze@nvidia.com>
CUDA Quantum Docs Bot: A preview of the documentation can be found here. |
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.
Review Summary:
The code looks great overall! You've followed best practices, and the implementation is clean and efficient. The logic is sound, and I appreciate the attention to detail in the structure.
Highlights:
- Code is well-organized and easy to follow.
- Proper handling of edge cases.
- Clear variable naming makes the code readable.
Overall, I approve this change and recommend merging it. Great work!
…eless-stores Signed-off-by: Anna Gringauze <agringauze@nvidia.com>
CUDA Quantum Docs Bot: A preview of the documentation can be found here. |
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.
"Useless" sounds a little judgmental or something to me. Maybe WAW elimination or WAW removal sounds less aggressive? heh
@@ -975,6 +975,29 @@ def RegToMem : Pass<"regtomem", "mlir::func::FuncOp"> { | |||
let dependentDialects = ["cudaq::cc::CCDialect", "quake::QuakeDialect"]; | |||
} | |||
|
|||
def RemoveUselessStores : Pass<"remove-useless-stores", "mlir::func::FuncOp"> { |
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.
I think we should call this "write-after-write-elimination`.
We can also make it a generic pass, since we may want to run it on more than func.func
.
def RemoveUselessStores : Pass<"remove-useless-stores", "mlir::func::FuncOp"> { | ||
let summary = "Remove stores that are overriden by other stores."; | ||
let description = [{ | ||
|
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.
Can we add more words here? I think the example is good, but examples aren't the best documentation as they can leave some unanswered questions.
// /// Detect if value is used in the op or its nested blocks. | ||
// static bool isUsed(Value v, Operation *op) { | ||
// for (auto opnd : op->getOperands()) | ||
// if (opnd == v) | ||
// return true; | ||
|
||
// for (auto ®ion : op->getRegions()) | ||
// for (auto &b : region) | ||
// for (auto &innerOp : b) | ||
// if (isUsed(v, &innerOp)) | ||
// return true; | ||
|
||
// return false; | ||
// } |
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.
Remove?
// // Found a use for a current ptr before the overriding store | ||
// if (currentPtr && isUsed(currentPtr, &op)) | ||
// return false; | ||
} | ||
} | ||
// } else { | ||
// // Found a use for a current ptr before the overriding store | ||
// if (currentPtr && isUsed(currentPtr, &op)) | ||
// return false; | ||
// } |
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.
Remove?
if (auto alloca = ptrOp.getDefiningOp<cudaq::cc::AllocaOp>()) | ||
return true; | ||
|
||
return false; |
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.
if (auto alloca = ptrOp.getDefiningOp<cudaq::cc::AllocaOp>()) | |
return true; | |
return false; | |
return isa_and_present<cudaq::cc::AllocaOp>(ptrOp.getDefiningOp()); |
|
||
auto block = store.getOperation()->getBlock(); | ||
for (auto &op : *block) { | ||
if (auto currentStore = dyn_cast<cudaq::cc::StoreOp>(&op)) { |
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.
I was thinking of doing this with an analysis step, first.
Have a DenseMap<Block*, DenseMap<Value, SmallVector<cudaq::cc::StoreOp*>>>
Scan the current operation's regions for cc::StoreOp
s. For each one found, add it to the map object by its block and ptr value argument.
After that go back over the map of maps, see if any of the vectors have > 1
element, and use dominance info to make sure no uses of the ptr value are dominated by the dominant store and dominate the post-dominant store other than any other stores in the block between the two (most dominant, most postdominant). Dominance here will catch uses into, e.g., cc::IfOp, etc.
If there is nothing but stores in the block between the two endpoint stores, go ahead and remove all but the postdominant one.
A more aggressive check would be to eliminate the dominant stores in a pair-wise, incremental approach. So if there is a store, if(with a load), store[*], store
, the dead store[*]
would be eliminated even though the first one cannot be removed.
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.
I'll try that, thanks! I do need the most aggressive approach it seems from the uccsd examples
Signed-off-by: Anna Gringauze <agringauze@nvidia.com>
Description
Add a pass for removing stores that are overridden by other stores
Example:
The in the last two stores, the first one can be removed because it is overridden by the next.