aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Analysis/ScalarEvolution.h5
-rw-r--r--include/llvm/Analysis/ScalarEvolutionExpressions.h21
-rw-r--r--lib/Analysis/ScalarEvolution.cpp74
-rw-r--r--unittests/Analysis/Makefile15
-rw-r--r--unittests/Analysis/ScalarEvolutionTest.cpp78
-rw-r--r--unittests/Makefile2
6 files changed, 162 insertions, 33 deletions
diff --git a/include/llvm/Analysis/ScalarEvolution.h b/include/llvm/Analysis/ScalarEvolution.h
index 1b27efb995..b052a82232 100644
--- a/include/llvm/Analysis/ScalarEvolution.h
+++ b/include/llvm/Analysis/ScalarEvolution.h
@@ -386,6 +386,11 @@ namespace llvm {
bool isKnownPredicateWithRanges(ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS);
+ /// forgetSCEVUnknown - V is being deleted or RAUW'd; remove the
+ /// SCEVUnknown for it from the uniquing map, and optionally
+ /// clear its contents to point to a replacement value.
+ void forgetSCEVUnknown(Value *V, Value *NewV);
+
public:
static char ID; // Pass identification, replacement for typeid
ScalarEvolution();
diff --git a/include/llvm/Analysis/ScalarEvolutionExpressions.h b/include/llvm/Analysis/ScalarEvolutionExpressions.h
index ec4ac071da..03f147e23e 100644
--- a/include/llvm/Analysis/ScalarEvolutionExpressions.h
+++ b/include/llvm/Analysis/ScalarEvolutionExpressions.h
@@ -524,11 +524,26 @@ namespace llvm {
friend class ScalarEvolution;
friend class ScalarEvolution::SCEVCallbackVH;
- // This should be an AssertingVH, however SCEVUnknowns are allocated in a
- // BumpPtrAllocator so their destructors are never called.
+ /// V - The Value represented by this SCEVUnknown.
+ /// This should be an AssertingVH, however SCEVUnknowns are allocated in a
+ /// BumpPtrAllocator so their destructors are never called.
Value *V;
+
+ /// UpdateList - When values are RAUW'd with new values, and the new
+ /// values already have their own SCEVUnknowns, they can end up with
+ /// muliple SCEVUnknowns. This pointer links them all together so that
+ /// they can all be updated when another RAUW happens.
+ SCEVUnknown *UpdateList;
+
+ /// getUpdateListBack - Return the last SCEVUnknown in te UpdateList.
+ SCEVUnknown *getUpdateListBack() {
+ SCEVUnknown *P = this;
+ while (SCEVUnknown *Q = P->UpdateList) P = Q;
+ return P;
+ }
+
SCEVUnknown(const FoldingSetNodeIDRef ID, Value *v) :
- SCEV(ID, scUnknown), V(v) {}
+ SCEV(ID, scUnknown), V(v), UpdateList(0) {}
public:
Value *getValue() const { return V; }
diff --git a/lib/Analysis/ScalarEvolution.cpp b/lib/Analysis/ScalarEvolution.cpp
index 7612f43f71..964093b069 100644
--- a/lib/Analysis/ScalarEvolution.cpp
+++ b/lib/Analysis/ScalarEvolution.cpp
@@ -3660,29 +3660,59 @@ void ScalarEvolution::forgetLoop(const Loop *L) {
}
}
-/// forgetValue - This method should be called by the client when it has
-/// changed a value in a way that may effect its value, or which may
-/// disconnect it from a def-use chain linking it to a loop.
-void ScalarEvolution::forgetValue(Value *V) {
- // If there's a SCEVUnknown tying this value into the SCEV
- // space, remove it from the folding set map. The SCEVUnknown
- // object and any other SCEV objects which reference it
- // (transitively) remain allocated, effectively leaked until
- // the underlying BumpPtrAllocator is freed.
- //
+/// forgetSCEVUnknown - V is being deleted or RAUW'd; remove the
+/// SCEVUnknown for it from the uniquing map, and optionally
+/// clear its contents to point to a replacement value.
+void ScalarEvolution::forgetSCEVUnknown(Value *V, Value *NewV) {
// This permits SCEV pointers to be used as keys in maps
// such as the ValuesAtScopes map.
+
+ // Check for an exisitng SCEVUnknown for V in the uniquing map.
FoldingSetNodeID ID;
ID.AddInteger(scUnknown);
ID.AddPointer(V);
void *IP;
if (SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) {
+ // Remove the old SCEVUnknown from the uniquing map, effectively
+ // leaking it from subsequent use by ScalarEvolution. There
+ // may be existing SCEVs live which still point to it though.
UniqueSCEVs.RemoveNode(S);
- // This isn't necessary, but we might as well remove the
- // value from the ValuesAtScopes map too.
- ValuesAtScopes.erase(S);
+ // If there's a replacement value, update the old SCEVUnknowns
+ // so that SCEVs which still point to it see the new value.
+ if (NewV) {
+ // Update the old SCEVUnknown and all SCEVUnknowns on its update list
+ // to point to NewV instead of V.
+ for (SCEVUnknown *U = cast<SCEVUnknown>(S); U; U = U->UpdateList) {
+ assert(U->V == V && "SCEVUnknown update list is inconsistent!");
+ U->V = NewV;
+ }
+
+ // Check for an existing SCEVUnknown for NewV in the uniquing map.
+ ID.clear();
+ ID.AddInteger(scUnknown);
+ ID.AddPointer(NewV);
+ if (SCEV *NewS = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) {
+ // The uniquing map already had an entry for the new
+ // value. Append the old SCEVUnknown (and its update list) to the
+ // new SCEVUnknown's update list.
+ cast<SCEVUnknown>(NewS)->getUpdateListBack()->UpdateList =
+ cast<SCEVUnknown>(S);
+ } else {
+ // The uniquing map did not have an entry for the new
+ // value yet. Set the old SCEVUnknown, which has now been
+ // updated, to be the SCEVUnknown in the uniquing map.
+ UniqueSCEVs.InsertNode(S, IP);
+ }
+ }
}
+}
+
+/// forgetValue - This method should be called by the client when it has
+/// changed a value in a way that may effect its value, or which may
+/// disconnect it from a def-use chain linking it to a loop.
+void ScalarEvolution::forgetValue(Value *V) {
+ forgetSCEVUnknown(V, 0);
Instruction *I = dyn_cast<Instruction>(V);
if (!I) return;
@@ -5692,24 +5722,10 @@ void ScalarEvolution::SCEVCallbackVH::deleted() {
void ScalarEvolution::SCEVCallbackVH::allUsesReplacedWith(Value *V) {
assert(SE && "SCEVCallbackVH called with a null ScalarEvolution!");
-
Value *Old = getValPtr();
- // If there's a SCEVUnknown tying this value into the SCEV
- // space, replace the SCEVUnknown's value with the new value
- // for the benefit of any SCEVs still referencing it, and
- // and remove it from the folding set map so that new scevs
- // don't reference it.
- FoldingSetNodeID ID;
- ID.AddInteger(scUnknown);
- ID.AddPointer(Old);
- void *IP;
- if (SCEVUnknown *S = cast_or_null<SCEVUnknown>(
- SE->UniqueSCEVs.FindNodeOrInsertPos(ID, IP))) {
- S->V = V;
- SE->UniqueSCEVs.RemoveNode(S);
- SE->ValuesAtScopes.erase(S);
- }
+ // First, update existing SCEVUnknowns.
+ SE->forgetSCEVUnknown(Old, V);
// Forget all the expressions associated with users of the old value,
// so that future queries will recompute the expressions using the new
diff --git a/unittests/Analysis/Makefile b/unittests/Analysis/Makefile
new file mode 100644
index 0000000000..f89240ec70
--- /dev/null
+++ b/unittests/Analysis/Makefile
@@ -0,0 +1,15 @@
+##===- unittests/Analysis/Makefile -------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+TESTNAME = Analysis
+LINK_COMPONENTS := core support target analysis ipa
+
+include $(LEVEL)/Makefile.config
+include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest
diff --git a/unittests/Analysis/ScalarEvolutionTest.cpp b/unittests/Analysis/ScalarEvolutionTest.cpp
new file mode 100644
index 0000000000..19bf90f073
--- /dev/null
+++ b/unittests/Analysis/ScalarEvolutionTest.cpp
@@ -0,0 +1,78 @@
+//===- ScalarEvolutionsTest.cpp - ScalarEvolution unit tests --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <llvm/Analysis/ScalarEvolutionExpressions.h>
+#include <llvm/GlobalVariable.h>
+#include <llvm/Constants.h>
+#include <llvm/LLVMContext.h>
+#include <llvm/Module.h>
+#include <llvm/PassManager.h>
+#include "gtest/gtest.h"
+
+namespace llvm {
+namespace {
+
+TEST(ScalarEvolutionsTest, ReturnInst) {
+ LLVMContext Context;
+ Module M("world", Context);
+
+ const FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context),
+ std::vector<const Type *>(), false);
+ Function *F = cast<Function>(M.getOrInsertFunction("f", FTy));
+ BasicBlock *BB = BasicBlock::Create(Context, "entry", F);
+ ReturnInst::Create(Context, 0, BB);
+
+ const Type *Ty = Type::getInt1Ty(Context);
+ Constant *Init = Constant::getNullValue(Ty);
+ Value *V0 = new GlobalVariable(M, Ty, false, GlobalValue::ExternalLinkage, Init, "V0");
+ Value *V1 = new GlobalVariable(M, Ty, false, GlobalValue::ExternalLinkage, Init, "V1");
+ Value *V2 = new GlobalVariable(M, Ty, false, GlobalValue::ExternalLinkage, Init, "V2");
+
+ // Create a ScalarEvolution and "run" it so that it gets initialized.
+ PassManager PM;
+ ScalarEvolution &SE = *new ScalarEvolution();
+ PM.add(&SE);
+ PM.run(M);
+
+ const SCEV *S0 = SE.getSCEV(V0);
+ const SCEV *S1 = SE.getSCEV(V1);
+ const SCEV *S2 = SE.getSCEV(V2);
+
+ const SCEV *P0 = SE.getAddExpr(S0, S0);
+ const SCEV *P1 = SE.getAddExpr(S1, S1);
+ const SCEV *P2 = SE.getAddExpr(S2, S2);
+
+ const SCEVMulExpr *M0 = cast<SCEVMulExpr>(P0);
+ const SCEVMulExpr *M1 = cast<SCEVMulExpr>(P1);
+ const SCEVMulExpr *M2 = cast<SCEVMulExpr>(P2);
+
+ EXPECT_EQ(cast<SCEVConstant>(M0->getOperand(0))->getValue()->getZExtValue(),
+ 2u);
+ EXPECT_EQ(cast<SCEVConstant>(M1->getOperand(0))->getValue()->getZExtValue(),
+ 2u);
+ EXPECT_EQ(cast<SCEVConstant>(M2->getOperand(0))->getValue()->getZExtValue(),
+ 2u);
+
+ // Before the RAUWs, these are all pointing to separate values.
+ EXPECT_EQ(cast<SCEVUnknown>(M0->getOperand(1))->getValue(), V0);
+ EXPECT_EQ(cast<SCEVUnknown>(M1->getOperand(1))->getValue(), V1);
+ EXPECT_EQ(cast<SCEVUnknown>(M2->getOperand(1))->getValue(), V2);
+
+ // Do some RAUWs.
+ V2->replaceAllUsesWith(V1);
+ V1->replaceAllUsesWith(V0);
+
+ // After the RAUWs, these should all be pointing to V0.
+ EXPECT_EQ(cast<SCEVUnknown>(M0->getOperand(1))->getValue(), V0);
+ EXPECT_EQ(cast<SCEVUnknown>(M1->getOperand(1))->getValue(), V0);
+ EXPECT_EQ(cast<SCEVUnknown>(M2->getOperand(1))->getValue(), V0);
+}
+
+} // end anonymous namespace
+} // end namespace llvm
diff --git a/unittests/Makefile b/unittests/Makefile
index 9f377cd744..0401cd1c67 100644
--- a/unittests/Makefile
+++ b/unittests/Makefile
@@ -9,7 +9,7 @@
LEVEL = ..
-PARALLEL_DIRS = ADT ExecutionEngine Support Transforms VMCore
+PARALLEL_DIRS = ADT ExecutionEngine Support Transforms VMCore Analysis
include $(LEVEL)/Makefile.common