diff --git a/include/llvm/IR/Constants.h b/include/llvm/IR/Constants.h index 31a0364b4b0..ab692dcf3d6 100644 --- a/include/llvm/IR/Constants.h +++ b/include/llvm/IR/Constants.h @@ -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 <> diff --git a/lib/IR/Constants.cpp b/lib/IR/Constants.cpp index c9ce2e826b9..d2c7ceee116 100644 --- a/lib/IR/Constants.cpp +++ b/lib/IR/Constants.cpp @@ -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(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(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 ValueOperands; for (op_iterator I = op_begin(), E = op_end(); I != E; ++I)