llvm.org GIT mirror llvm / b03916a
IR: Fix ConstantExpr::replaceUsesOfWithOnConstant() Change `ConstantExpr` to follow the model the other constants are using: only malloc a replacement if it's going to be used. This fixes a subtle bug where if an API user had used `ConstantExpr::get()` already to create the replacement but hadn't given it any users, we'd delete the replacement. This relies on r216015 to thread `OnlyIfReduced` through `ConstantExpr::getWithOperands()`. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216016 91177308-0d34-0410-b5e6-96231b3b80d8 Duncan P. N. Exon Smith 6 years ago
3 changed file(s) with 38 addition(s) and 58 deletion(s). Raw diff Collapse all Expand all
11411141 void setValueSubclassData(unsigned short D) {
11421142 Value::setValueSubclassData(D);
11431143 }
1144
1145 /// \brief Check whether this can become its replacement.
1146 ///
1147 /// For use during \a replaceUsesOfWithOnConstant(), check whether we know
1148 /// how to turn this into \a Replacement, thereby reducing RAUW traffic.
1149 bool canBecomeReplacement(const Constant *Replacement) const;
11501144 };
11511145
11521146 template <>
28562856 Constant *To = cast(ToV);
28572857
28582858 SmallVector NewOps;
2859 unsigned NumUpdated = 0;
28592860 for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
28602861 Constant *Op = getOperand(i);
2861 NewOps.push_back(Op == From ? To : Op);
2862 }
2863
2864 Constant *Replacement = getWithOperands(NewOps);
2865 assert(Replacement != this && "I didn't contain From!");
2866
2867 // Check if Replacement has no users (and is the same type). Ideally, this
2868 // check would be done *before* creating Replacement, but threading this
2869 // through constant-folding isn't trivial.
2870 if (canBecomeReplacement(Replacement)) {
2871 // Avoid unnecessary RAUW traffic.
2872 auto &ExprConstants = getType()->getContext().pImpl->ExprConstants;
2873 ExprConstants.remove(this);
2874
2875 auto *CE = cast(Replacement);
2876 for (unsigned I = 0, E = getNumOperands(); I != E; ++I)
2877 // Only set the operands that have actually changed.
2878 if (getOperand(I) != CE->getOperand(I))
2879 setOperand(I, CE->getOperand(I));
2880
2881 CE->destroyConstant();
2882 ExprConstants.insert(this);
2862 if (Op == From) {
2863 ++NumUpdated;
2864 Op = To;
2865 }
2866 NewOps.push_back(Op);
2867 }
2868 assert(NumUpdated && "I didn't contain From!");
2869
2870 if (Constant *C = getWithOperands(NewOps, getType(), true)) {
2871 replaceUsesOfWithOnConstantImpl(C);
28832872 return;
28842873 }
28852874
2886 // Everyone using this now uses the replacement.
2887 replaceAllUsesWith(Replacement);
2888
2889 // Delete the old constant!
2890 destroyConstant();
2891 }
2892
2893 bool ConstantExpr::canBecomeReplacement(const Constant *Replacement) const {
2894 // If Replacement already has users, use it regardless.
2895 if (!Replacement->use_empty())
2896 return false;
2897
2898 // Check for anything that could have changed during constant-folding.
2899 if (getValueID() != Replacement->getValueID())
2900 return false;
2901 const auto *CE = cast(Replacement);
2902 if (getOpcode() != CE->getOpcode())
2903 return false;
2904 if (getNumOperands() != CE->getNumOperands())
2905 return false;
2906 if (getRawSubclassOptionalData() != CE->getRawSubclassOptionalData())
2907 return false;
2908 if (isCompare())
2909 if (getPredicate() != CE->getPredicate())
2910 return false;
2911 if (hasIndices())
2912 if (getIndices() != CE->getIndices())
2913 return false;
2914
2915 return true;
2875 // Update to the new value.
2876 if (Constant *C = getContext().pImpl->ExprConstants.replaceOperandsInPlace(
2877 NewOps, this, From, To, NumUpdated, U - OperandList))
2878 replaceUsesOfWithOnConstantImpl(C);
29162879 }
29172880
29182881 Instruction *ConstantExpr::getAsInstruction() {
298298 ASSERT_EQ(A01, RefArray->getInitializer());
299299 }
300300
301 TEST(ConstantsTest, ConstantExprReplaceWithConstant) {
302 LLVMContext Context;
303 std::unique_ptr M(new Module("MyModule", Context));
304
305 Type *IntTy = Type::getInt8Ty(Context);
306 Constant *G1 = new GlobalVariable(*M, IntTy, false,
307 GlobalValue::ExternalLinkage, nullptr);
308 Constant *G2 = new GlobalVariable(*M, IntTy, false,
309 GlobalValue::ExternalLinkage, nullptr);
310 ASSERT_NE(G1, G2);
311
312 Constant *Int1 = ConstantExpr::getPtrToInt(G1, IntTy);
313 Constant *Int2 = ConstantExpr::getPtrToInt(G2, IntTy);
314 ASSERT_NE(Int1, Int2);
315
316 GlobalVariable *Ref =
317 new GlobalVariable(*M, IntTy, false, GlobalValue::ExternalLinkage, Int1);
318 ASSERT_EQ(Int1, Ref->getInitializer());
319
320 G1->replaceAllUsesWith(G2);
321 ASSERT_EQ(Int2, Ref->getInitializer());
322 }
323
301324 } // end anonymous namespace
302325 } // end namespace llvm