diff options
-rw-r--r-- | include/llvm/Analysis/ScalarEvolution.h | 5 | ||||
-rw-r--r-- | include/llvm/Analysis/ScalarEvolutionExpressions.h | 21 | ||||
-rw-r--r-- | lib/Analysis/ScalarEvolution.cpp | 74 | ||||
-rw-r--r-- | unittests/Analysis/Makefile | 15 | ||||
-rw-r--r-- | unittests/Analysis/ScalarEvolutionTest.cpp | 78 | ||||
-rw-r--r-- | unittests/Makefile | 2 |
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 |