IR: Reduce RAUW traffic in ConstantExpr

Avoid RAUW-ing `ConstantExpr` when an operand changes unless the new
`ConstantExpr` already has users.  This prevents the RAUW from rippling
up the expression tree unnecessarily.

This commit indirectly adds test coverage for r215953 (this is how I
came across the bug).

This is part of PR20515.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@215960 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Duncan P. N. Exon Smith 2014-08-19 01:12:53 +00:00
parent fe0bf8fbf9
commit 1cfbb6358c
2 changed files with 50 additions and 0 deletions

View File

@ -1107,6 +1107,12 @@ private:
void setValueSubclassData(unsigned short D) {
Value::setValueSubclassData(D);
}
/// \brief Check whether this can become its replacement.
///
/// For use during \a replaceUsesOfWithOnConstant(), check whether we know
/// how to turn this into \a Replacement, thereby reducing RAUW traffic.
bool canBecomeReplacement(const Constant *Replacement) const;
};
template <>

View File

@ -2836,6 +2836,25 @@ void ConstantExpr::replaceUsesOfWithOnConstant(Value *From, Value *ToV,
Constant *Replacement = getWithOperands(NewOps);
assert(Replacement != this && "I didn't contain From!");
// Check if Replacement has no users (and is the same type). Ideally, this
// check would be done *before* creating Replacement, but threading this
// through constant-folding isn't trivial.
if (canBecomeReplacement(Replacement)) {
// Avoid unnecessary RAUW traffic.
auto &ExprConstants = getType()->getContext().pImpl->ExprConstants;
ExprConstants.remove(this);
auto *CE = cast<ConstantExpr>(Replacement);
for (unsigned I = 0, E = getNumOperands(); I != E; ++I)
// Only set the operands that have actually changed.
if (getOperand(I) != CE->getOperand(I))
setOperand(I, CE->getOperand(I));
CE->destroyConstant();
ExprConstants.insert(this);
return;
}
// Everyone using this now uses the replacement.
replaceAllUsesWith(Replacement);
@ -2843,6 +2862,31 @@ void ConstantExpr::replaceUsesOfWithOnConstant(Value *From, Value *ToV,
destroyConstant();
}
bool ConstantExpr::canBecomeReplacement(const Constant *Replacement) const {
// If Replacement already has users, use it regardless.
if (!Replacement->use_empty())
return false;
// Check for anything that could have changed during constant-folding.
if (getValueID() != Replacement->getValueID())
return false;
const auto *CE = cast<ConstantExpr>(Replacement);
if (getOpcode() != CE->getOpcode())
return false;
if (getNumOperands() != CE->getNumOperands())
return false;
if (getRawSubclassOptionalData() != CE->getRawSubclassOptionalData())
return false;
if (isCompare())
if (getPredicate() != CE->getPredicate())
return false;
if (hasIndices())
if (getIndices() != CE->getIndices())
return false;
return true;
}
Instruction *ConstantExpr::getAsInstruction() {
SmallVector<Value*,4> ValueOperands;
for (op_iterator I = op_begin(), E = op_end(); I != E; ++I)