-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[GVN] Improve processBlock for instruction erasure #131753
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
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Madhur Amilkanthwar (madhur13490) ChangesThis patch deletes the instructions right away by using the approapriate iterators. Thus avoids collecting the instructions in a vector and then doing the erasure. Full diff: https://github.com/llvm/llvm-project/pull/131753.diff 2 Files Affected:
diff --git a/llvm/include/llvm/Transforms/Scalar/GVN.h b/llvm/include/llvm/Transforms/Scalar/GVN.h
index c8be390799836..01b3763fb5581 100644
--- a/llvm/include/llvm/Transforms/Scalar/GVN.h
+++ b/llvm/include/llvm/Transforms/Scalar/GVN.h
@@ -25,6 +25,8 @@
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
+#include "llvm/Transforms/Utils/Local.h"
#include <cstdint>
#include <optional>
#include <utility>
@@ -137,9 +139,11 @@ class GVNPass : public PassInfoMixin<GVNPass> {
/// This removes the specified instruction from
/// our various maps and marks it for deletion.
- void markInstructionForDeletion(Instruction *I) {
+ void doInstructionDeletion(Instruction *I) {
+ salvageKnowledge(I, AC);
+ salvageDebugInfo(*I);
VN.erase(I);
- InstrsToErase.push_back(I);
+ removeInstruction(I);
}
DominatorTree &getDominatorTree() const { return *DT; }
@@ -306,7 +310,6 @@ class GVNPass : public PassInfoMixin<GVNPass> {
// propagate to any successors. Entries added mid-block are applied
// to the remaining instructions in the block.
SmallMapVector<Value *, Value *, 4> ReplaceOperandsWithMap;
- SmallVector<Instruction *, 8> InstrsToErase;
// Map the block to reversed postorder traversal number. It is used to
// find back edge easily.
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index 85fcdd95f5d87..5550721f8d249 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -730,8 +730,9 @@ void GVNPass::ValueTable::erase(Value *V) {
/// verifyRemoved - Verify that the value is removed from all internal data
/// structures.
void GVNPass::ValueTable::verifyRemoved(const Value *V) const {
- assert(!valueNumbering.contains(V) &&
- "Inst still occurs in value numbering map!");
+ if (V != nullptr)
+ assert(!valueNumbering.contains(V) &&
+ "Inst still occurs in value numbering map!");
}
//===----------------------------------------------------------------------===//
@@ -1574,7 +1575,7 @@ void GVNPass::eliminatePartiallyRedundantLoad(
I->setDebugLoc(Load->getDebugLoc());
if (V->getType()->isPtrOrPtrVectorTy())
MD->invalidateCachedPointerInfo(V);
- markInstructionForDeletion(Load);
+ doInstructionDeletion(Load);
ORE->emit([&]() {
return OptimizationRemark(DEBUG_TYPE, "LoadPRE", Load)
<< "load eliminated by PRE";
@@ -1798,7 +1799,7 @@ bool GVNPass::PerformLoadPRE(LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
// Erase instructions generated by the failed PHI translation before
// trying to number them. PHI translation might insert instructions
// in basic blocks other than the current one, and we delete them
- // directly, as markInstructionForDeletion only allows removing from the
+ // directly, as doInstructionDeletion only allows removing from the
// current basic block.
NewInsts.pop_back_val()->eraseFromParent();
}
@@ -1997,7 +1998,7 @@ bool GVNPass::processNonLocalLoad(LoadInst *Load) {
I->setDebugLoc(Load->getDebugLoc());
if (V->getType()->isPtrOrPtrVectorTy())
MD->invalidateCachedPointerInfo(V);
- markInstructionForDeletion(Load);
+ doInstructionDeletion(Load);
++NumGVNLoad;
reportLoadElim(Load, V, ORE);
return true;
@@ -2067,7 +2068,7 @@ bool GVNPass::processAssumeIntrinsic(AssumeInst *IntrinsicI) {
}
}
if (isAssumeWithEmptyBundle(*IntrinsicI)) {
- markInstructionForDeletion(IntrinsicI);
+ doInstructionDeletion(IntrinsicI);
return true;
}
return false;
@@ -2179,7 +2180,7 @@ bool GVNPass::processLoad(LoadInst *L) {
return false;
if (L->use_empty()) {
- markInstructionForDeletion(L);
+ doInstructionDeletion(L);
return true;
}
@@ -2209,13 +2210,13 @@ bool GVNPass::processLoad(LoadInst *L) {
// MaterializeAdjustedValue is responsible for combining metadata.
ICF->removeUsersOf(L);
L->replaceAllUsesWith(AvailableValue);
- markInstructionForDeletion(L);
if (MSSAU)
MSSAU->removeMemoryAccess(L);
++NumGVNLoad;
reportLoadElim(L, AvailableValue, ORE);
// Tell MDA to reexamine the reused pointer since we might have more
// information after forwarding it.
+ doInstructionDeletion(L);
if (MD && AvailableValue->getType()->isPtrOrPtrVectorTy())
MD->invalidateCachedPointerInfo(AvailableValue);
return true;
@@ -2605,7 +2606,7 @@ bool GVNPass::processInstruction(Instruction *I) {
Changed = true;
}
if (isInstructionTriviallyDead(I, TLI)) {
- markInstructionForDeletion(I);
+ doInstructionDeletion(I);
Changed = true;
}
if (Changed) {
@@ -2723,7 +2724,7 @@ bool GVNPass::processInstruction(Instruction *I) {
patchAndReplaceAllUsesWith(I, Repl);
if (MD && Repl->getType()->isPtrOrPtrVectorTy())
MD->invalidateCachedPointerInfo(Repl);
- markInstructionForDeletion(I);
+ doInstructionDeletion(I);
return true;
}
@@ -2799,10 +2800,6 @@ bool GVNPass::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
}
bool GVNPass::processBlock(BasicBlock *BB) {
- // FIXME: Kill off InstrsToErase by doing erasing eagerly in a helper function
- // (and incrementing BI before processing an instruction).
- assert(InstrsToErase.empty() &&
- "We expect InstrsToErase to be empty across iterations");
if (DeadBlocks.count(BB))
return false;
@@ -2820,41 +2817,12 @@ bool GVNPass::processBlock(BasicBlock *BB) {
VN.erase(PN);
removeInstruction(PN);
}
-
- for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();
- BI != BE;) {
+ for (BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE;) {
+ Instruction *Inst = &*BI++;
if (!ReplaceOperandsWithMap.empty())
- ChangedFunction |= replaceOperandsForInBlockEquality(&*BI);
- ChangedFunction |= processInstruction(&*BI);
-
- if (InstrsToErase.empty()) {
- ++BI;
- continue;
- }
-
- // If we need some instructions deleted, do it now.
- NumGVNInstr += InstrsToErase.size();
-
- // Avoid iterator invalidation.
- bool AtStart = BI == BB->begin();
- if (!AtStart)
- --BI;
-
- for (auto *I : InstrsToErase) {
- assert(I->getParent() == BB && "Removing instruction from wrong block?");
- LLVM_DEBUG(dbgs() << "GVN removed: " << *I << '\n');
- salvageKnowledge(I, AC);
- salvageDebugInfo(*I);
- removeInstruction(I);
- }
- InstrsToErase.clear();
-
- if (AtStart)
- BI = BB->begin();
- else
- ++BI;
+ ChangedFunction |= replaceOperandsForInBlockEquality(Inst);
+ ChangedFunction |= processInstruction(Inst);
}
-
return ChangedFunction;
}
|
All tests pass but not sure how to construct a test for this patch. Suggestions welcome! |
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.
Could you provide more details on the motivation for this change? Is it just to resolve the FIXME or something else?
It looks like the stack-layout-remark.c clang test crashes.
yes, primarily FIXME. Nothing else as such which motivates. The change is an optimization in the process of handling instructions by avoiding vector population just for the erasure.
Fixed in the current revision. Thanks! |
@nikic Gentle ping! |
Ping to reviewers! @antoniofrighetto can you please have a look? |
@@ -25,6 +25,8 @@ | |||
#include "llvm/IR/ValueHandle.h" | |||
#include "llvm/Support/Allocator.h" | |||
#include "llvm/Support/Compiler.h" | |||
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h" |
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 remove this from the C++ file?
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.
Done
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.
IMHO it would be better to move the definition of doInstructionDeletion to the source file. There's no need to have it in the header.
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.
Done
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 drop these includes now.
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't remove. salvage* is provided by AssumeBundleBuilder
.
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.
Yes, but it's no longer necessary in the header. You can drop the includes in the header and restore the AssumeBundleBuilder.h include in the cpp file.
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.
You can drop the includes in the header
Do you mean just the AssumeBundleBuilder
?
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 mean the two you added.
@@ -25,6 +25,8 @@ | |||
#include "llvm/IR/ValueHandle.h" | |||
#include "llvm/Support/Allocator.h" | |||
#include "llvm/Support/Compiler.h" | |||
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h" |
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.
IMHO it would be better to move the definition of doInstructionDeletion to the source file. There's no need to have it in the header.
✅ With the latest revision this PR passed the C/C++ code formatter. |
@antoniofrighetto @nikic Addressed all review comments. The thing about guarding assert under |
Gentle ping @antoniofrighetto @nikic ! |
@@ -25,6 +25,8 @@ | |||
#include "llvm/IR/ValueHandle.h" | |||
#include "llvm/Support/Allocator.h" | |||
#include "llvm/Support/Compiler.h" | |||
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h" |
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 drop these includes now.
This patch deletes the instructions right away by using the approapriate iterators. Thus avoids collecting the instructions in a vector and then doing the erasure.
@nikic Removed the new includes from |
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.
LGTM
This patch deletes the instructions immediately in core GVN processing by using the appropriate iterators. Thus, it avoids collecting the instructions in a vector and then doing the erasure.
This patch deletes the instructions right away by using the approapriate iterators. Thus avoids collecting the instructions in a vector and then doing the erasure.