mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-02 00:16:25 +00:00
Factor out some of the code for updating old SCEVUnknown values, and
extend it to handle the case where multiple RAUWs affect a single SCEVUnknown. Add a ScalarEvolution unittest to test for this situation. llvm-svn: 109705
This commit is contained in:
parent
712152a68e
commit
ea1486b53c
@ -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();
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
15
unittests/Analysis/Makefile
Normal file
15
unittests/Analysis/Makefile
Normal file
@ -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
|
78
unittests/Analysis/ScalarEvolutionTest.cpp
Normal file
78
unittests/Analysis/ScalarEvolutionTest.cpp
Normal file
@ -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
|
@ -9,7 +9,7 @@
|
||||
|
||||
LEVEL = ..
|
||||
|
||||
PARALLEL_DIRS = ADT ExecutionEngine Support Transforms VMCore
|
||||
PARALLEL_DIRS = ADT ExecutionEngine Support Transforms VMCore Analysis
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user