[llvm] r215960 - IR: Reduce RAUW traffic in ConstantExpr

Duncan P. N. Exon Smith dexonsmith at apple.com
Mon Aug 18 18:12:53 PDT 2014


Author: dexonsmith
Date: Mon Aug 18 20:12:53 2014
New Revision: 215960

URL: http://llvm.org/viewvc/llvm-project?rev=215960&view=rev
Log:
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.

Modified:
    llvm/trunk/include/llvm/IR/Constants.h
    llvm/trunk/lib/IR/Constants.cpp

Modified: llvm/trunk/include/llvm/IR/Constants.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Constants.h?rev=215960&r1=215959&r2=215960&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/Constants.h (original)
+++ llvm/trunk/include/llvm/IR/Constants.h Mon Aug 18 20:12:53 2014
@@ -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 <>

Modified: llvm/trunk/lib/IR/Constants.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Constants.cpp?rev=215960&r1=215959&r2=215960&view=diff
==============================================================================
--- llvm/trunk/lib/IR/Constants.cpp (original)
+++ llvm/trunk/lib/IR/Constants.cpp Mon Aug 18 20:12:53 2014
@@ -2836,6 +2836,25 @@ void ConstantExpr::replaceUsesOfWithOnCo
   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::replaceUsesOfWithOnCo
   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)





More information about the llvm-commits mailing list