Refactor RegionStore::RemoveDeadBindings to use the same core

cluster analysis algorithm as RegionStore::InvalidateRegions().

Beyond simplifying the algorithm significantly, we no longer
need to build subregion maps in RemoveDeadBindings().  This
and other changes cause a significant speedup: the time to
analyze sqlite3.c (single core) drops by 14%.

llvm-svn: 98144
This commit is contained in:
Ted Kremenek 2010-03-10 07:20:03 +00:00
parent a2536b642c
commit ba2e6c6b73
1 changed files with 87 additions and 87 deletions

View File

@ -41,25 +41,25 @@ public:
enum Kind { Direct = 0x0, Default = 0x1 };
private:
llvm ::PointerIntPair<const MemRegion*, 1> P;
uint64_t Offset;
uint64_t Offset;
explicit BindingKey(const MemRegion *r, uint64_t offset, Kind k)
: P(r, (unsigned) k), Offset(offset) { assert(r); }
public:
bool isDefault() const { return P.getInt() == Default; }
bool isDirect() const { return P.getInt() == Direct; }
const MemRegion *getRegion() const { return P.getPointer(); }
uint64_t getOffset() const { return Offset; }
void Profile(llvm::FoldingSetNodeID& ID) const {
ID.AddPointer(P.getOpaqueValue());
ID.AddInteger(Offset);
}
static BindingKey Make(const MemRegion *R, Kind k);
bool operator<(const BindingKey &X) const {
if (P.getOpaqueValue() < X.P.getOpaqueValue())
return true;
@ -67,16 +67,16 @@ public:
return false;
return Offset < X.Offset;
}
bool operator==(const BindingKey &X) const {
return P.getOpaqueValue() == X.P.getOpaqueValue() &&
Offset == X.Offset;
}
};
};
} // end anonymous namespace
namespace llvm {
static inline
static inline
llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) {
os << '(' << K.getRegion() << ',' << K.getOffset()
<< ',' << (K.isDirect() ? "direct" : "default")
@ -174,7 +174,7 @@ public:
void process(llvm::SmallVectorImpl<const SubRegion*> &WL, const SubRegion *R);
~RegionStoreSubRegionMap() {}
const Set *getSubRegions(const MemRegion *Parent) const {
Map::const_iterator I = M.find(Parent);
return I == M.end() ? NULL : &I->second;
@ -196,11 +196,11 @@ public:
}
};
class RegionStoreManager : public StoreManager {
const RegionStoreFeatures Features;
RegionBindings::Factory RBFactory;
typedef llvm::DenseMap<Store, RegionStoreSubRegionMap*> SMCache;
SMCache SC;
@ -226,10 +226,10 @@ public:
/// getDefaultBinding - Returns an SVal* representing an optional default
/// binding associated with a region and its subregions.
Optional<SVal> getDefaultBinding(RegionBindings B, const MemRegion *R);
/// setImplicitDefaultValue - Set the default binding for the provided
/// MemRegion to the value implicitly defined for compound literals when
/// the value is not specified.
/// the value is not specified.
Store setImplicitDefaultValue(Store store, const MemRegion *R, QualType T);
/// ArrayToPointer - Emulates the "decay" of an array to a pointer
@ -250,11 +250,11 @@ public:
// Binding values to regions.
//===-------------------------------------------------------------------===//
Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E,
Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E,
unsigned Count, InvalidatedSymbols *IS) {
return RegionStoreManager::InvalidateRegions(store, &R, &R+1, E, Count, IS);
}
Store InvalidateRegions(Store store,
const MemRegion * const *Begin,
const MemRegion * const *End,
@ -262,7 +262,7 @@ public:
InvalidatedSymbols *IS);
public: // Made public for helper classes.
void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
RegionStoreSubRegionMap &M);
@ -270,17 +270,17 @@ public: // Made public for helper classes.
RegionBindings Add(RegionBindings B, const MemRegion *R,
BindingKey::Kind k, SVal V);
const SVal *Lookup(RegionBindings B, BindingKey K);
const SVal *Lookup(RegionBindings B, const MemRegion *R, BindingKey::Kind k);
RegionBindings Remove(RegionBindings B, BindingKey K);
RegionBindings Remove(RegionBindings B, const MemRegion *R,
BindingKey::Kind k);
RegionBindings Remove(RegionBindings B, const MemRegion *R) {
return Remove(Remove(B, R, BindingKey::Direct), R, BindingKey::Default);
}
}
Store Remove(Store store, BindingKey K);
@ -306,7 +306,7 @@ public: // Part of public interface to class.
Store KillStruct(Store store, const TypedRegion* R);
Store Remove(Store store, Loc LV);
//===------------------------------------------------------------------===//
// Loading values from regions.
@ -373,7 +373,7 @@ public: // Part of public interface to class.
//===------------------------------------------------------------------===//
const GRState *setExtent(const GRState *state,const MemRegion* R,SVal Extent);
DefinedOrUnknownSVal getSizeInElements(const GRState *state,
DefinedOrUnknownSVal getSizeInElements(const GRState *state,
const MemRegion* R, QualType EleTy);
//===------------------------------------------------------------------===//
@ -699,7 +699,7 @@ Store RegionStoreManager::InvalidateRegions(Store store,
StateMgr.getValueManager());
return W.InvalidateRegions(store, I, E, Ex, Count);
}
//===----------------------------------------------------------------------===//
// Extents for regions.
//===----------------------------------------------------------------------===//
@ -710,7 +710,7 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
switch (R->getKind()) {
case MemRegion::CXXThisRegionKind:
assert(0 && "Cannot get size of 'this' region");
assert(0 && "Cannot get size of 'this' region");
case MemRegion::GenericMemSpaceRegionKind:
case MemRegion::StackLocalsSpaceRegionKind:
case MemRegion::StackArgumentsSpaceRegionKind:
@ -743,7 +743,7 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
if (!CI)
return UnknownVal();
CharUnits RegionSize =
CharUnits RegionSize =
CharUnits::fromQuantity(CI->getValue().getSExtValue());
CharUnits EleSize = getContext().getTypeSizeInChars(EleTy);
assert(RegionSize % EleSize == 0);
@ -864,7 +864,7 @@ SVal RegionStoreManager::EvalBinOp(BinaryOperator::Opcode Op, Loc L, NonLoc R,
// Not yet handled.
case MemRegion::VarRegionKind:
case MemRegion::StringRegionKind: {
}
// Fall-through.
case MemRegion::CompoundLiteralRegionKind:
@ -908,13 +908,13 @@ SVal RegionStoreManager::EvalBinOp(BinaryOperator::Opcode Op, Loc L, NonLoc R,
MRMgr.getElementRegion(ER->getElementType(), NewIdx,
ER->getSuperRegion(), getContext());
return ValMgr.makeLoc(NewER);
}
}
if (0 == Base->getValue()) {
const MemRegion* NewER =
MRMgr.getElementRegion(ER->getElementType(), R,
ER->getSuperRegion(), getContext());
return ValMgr.makeLoc(NewER);
}
return ValMgr.makeLoc(NewER);
}
}
return UnknownVal();
@ -924,10 +924,10 @@ SVal RegionStoreManager::EvalBinOp(BinaryOperator::Opcode Op, Loc L, NonLoc R,
// Loading values from regions.
//===----------------------------------------------------------------------===//
Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
const MemRegion *R) {
if (const SVal *V = Lookup(B, R, BindingKey::Direct))
return *V;
return *V;
return Optional<SVal>();
}
@ -947,10 +947,10 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
Optional<SVal> RegionStoreManager::getBinding(RegionBindings B,
const MemRegion *R) {
if (Optional<SVal> V = getDirectBinding(B, R))
return V;
return getDefaultBinding(B, R);
}
@ -988,12 +988,12 @@ RegionStoreManager::GetElementZeroRegion(const MemRegion *R, QualType T) {
SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
assert(!isa<UnknownVal>(L) && "location unknown");
assert(!isa<UndefinedVal>(L) && "location undefined");
// FIXME: Is this even possible? Shouldn't this be treated as a null
// dereference at a higher level?
if (isa<loc::ConcreteInt>(L))
return UndefinedVal();
const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion();
if (isa<AllocaRegion>(MR) || isa<SymbolicRegion>(MR))
@ -1053,7 +1053,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
// bound regions (e.g., several bound bytes), or could be a subset of
// a larger value.
return CastRetrievedVal(RetrieveElement(store, ER), ER, T, false);
}
}
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
// FIXME: Here we actually perform an implicit conversion from the loaded
@ -1071,7 +1071,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
// that blow past the extent of the variable. If the address of the
// variable is reinterpretted, it is possible we stored a different value
// that could fit within the variable. Either we need to cast these when
// storing them or reinterpret them lazily (as we do here).
// storing them or reinterpret them lazily (as we do here).
return CastRetrievedVal(RetrieveVar(store, VR), VR, T, false);
}
@ -1120,7 +1120,7 @@ RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) {
return std::make_pair(X.first,
MRMgr.getFieldRegionWithSuper(FR, X.second));
}
// The NULL MemRegion indicates an non-existent lazy binding. A NULL Store is
// The NULL MemRegion indicates an non-existent lazy binding. A NULL Store is
// possible for a valid lazy binding.
return std::make_pair((Store) 0, (const MemRegion *) 0);
}
@ -1136,13 +1136,13 @@ SVal RegionStoreManager::RetrieveElement(Store store,
// Check if the region is an element region of a string literal.
if (const StringRegion *StrR=dyn_cast<StringRegion>(superR)) {
// FIXME: Handle loads from strings where the literal is treated as
// FIXME: Handle loads from strings where the literal is treated as
// an integer, e.g., *((unsigned int*)"hello")
ASTContext &Ctx = getContext();
QualType T = Ctx.getAsArrayType(StrR->getValueType(Ctx))->getElementType();
if (T != Ctx.getCanonicalType(R->getElementType()))
return UnknownVal();
const StringLiteral *Str = StrR->getStringLiteral();
SVal Idx = R->getIndex();
if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
@ -1179,7 +1179,7 @@ SVal RegionStoreManager::RetrieveElement(Store store,
// Other cases: give up.
return UnknownVal();
}
return RetrieveFieldOrElementCommon(store, R, R->getElementType(), superR);
}
@ -1292,8 +1292,8 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
const VarDecl *VD = R->getDecl();
QualType T = VD->getType();
const MemSpaceRegion *MS = R->getMemorySpace();
if (isa<UnknownSpaceRegion>(MS) ||
if (isa<UnknownSpaceRegion>(MS) ||
isa<StackArgumentsSpaceRegion>(MS))
return ValMgr.getRegionValueSymbolVal(R);
@ -1306,9 +1306,9 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) {
if (T->isPointerType())
return ValMgr.makeNull();
return UnknownVal();
return UnknownVal();
}
return UndefinedVal();
}
@ -1426,7 +1426,7 @@ Store RegionStoreManager::Bind(Store store, Loc L, SVal V) {
// Binding directly to a symbolic region should be treated as binding
// to element 0.
QualType T = SR->getSymbol()->getType(getContext());
// FIXME: Is this the right way to handle symbols that are references?
if (const PointerType *PT = T->getAs<PointerType>())
T = PT->getPointeeType();
@ -1441,7 +1441,7 @@ Store RegionStoreManager::Bind(Store store, Loc L, SVal V) {
return Add(B, R, BindingKey::Direct, V).getRoot();
}
Store RegionStoreManager::BindDecl(Store store, const VarRegion *VR,
Store RegionStoreManager::BindDecl(Store store, const VarRegion *VR,
SVal InitVal) {
QualType T = VR->getDecl()->getType();
@ -1484,19 +1484,19 @@ Store RegionStoreManager::setImplicitDefaultValue(Store store,
return Add(B, R, BindingKey::Default, V).getRoot();
}
Store RegionStoreManager::BindArray(Store store, const TypedRegion* R,
Store RegionStoreManager::BindArray(Store store, const TypedRegion* R,
SVal Init) {
ASTContext &Ctx = getContext();
const ArrayType *AT =
cast<ArrayType>(Ctx.getCanonicalType(R->getValueType(Ctx)));
QualType ElementTy = AT->getElementType();
QualType ElementTy = AT->getElementType();
Optional<uint64_t> Size;
if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(AT))
Size = CAT->getSize().getZExtValue();
// Check if the init expr is a StringLiteral.
if (isa<loc::MemRegionVal>(Init)) {
const MemRegion* InitR = cast<loc::MemRegionVal>(Init).getRegion();
@ -1508,11 +1508,11 @@ Store RegionStoreManager::BindArray(Store store, const TypedRegion* R,
// Copy bytes from the string literal into the target array. Trailing bytes
// in the array that are not covered by the string literal are initialized
// to zero.
// We assume that string constants are bound to
// constant arrays.
uint64_t size = Size.getValue();
for (uint64_t i = 0; i < size; ++i, ++j) {
if (j >= len)
break;
@ -1533,10 +1533,10 @@ Store RegionStoreManager::BindArray(Store store, const TypedRegion* R,
return CopyLazyBindings(*LCV, store, R);
// Remaining case: explicit compound values.
if (Init.isUnknown())
return setImplicitDefaultValue(store, R, ElementTy);
return setImplicitDefaultValue(store, R, ElementTy);
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(Init);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
uint64_t i = 0;
@ -1652,14 +1652,14 @@ Store RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
BindingKey BindingKey::Make(const MemRegion *R, Kind k) {
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
const RegionRawOffset &O = ER->getAsRawOffset();
if (O.getRegion())
return BindingKey(O.getRegion(), O.getByteOffset(), k);
// FIXME: There are some ElementRegions for which we cannot compute
// raw offsets yet, including regions with symbolic offsets.
}
return BindingKey(R, 0, k);
}
@ -1699,7 +1699,7 @@ Store RegionStoreManager::Remove(Store store, BindingKey K) {
//===----------------------------------------------------------------------===//
// State pruning.
//===----------------------------------------------------------------------===//
Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
@ -1711,48 +1711,48 @@ Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
// The backmap from regions to subregions.
llvm::OwningPtr<RegionStoreSubRegionMap>
SubRegions(getRegionStoreSubRegionMap(store));
// Do a pass over the regions in the store. For VarRegions we check if
// the variable is still live and if so add it to the list of live roots.
// For other regions we populate our region backmap.
llvm::SmallVector<const MemRegion*, 10> IntermediateRoots;
// Scan the direct bindings for "intermediate" roots.
for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const MemRegion *R = I.getKey().getRegion();
IntermediateRoots.push_back(R);
}
// Process the "intermediate" roots to find if they are referenced by
// real roots.
llvm::SmallVector<RBDNode, 10> WorkList;
llvm::SmallVector<RBDNode, 10> Postponed;
llvm::DenseSet<const MemRegion*> IntermediateVisited;
while (!IntermediateRoots.empty()) {
const MemRegion* R = IntermediateRoots.back();
IntermediateRoots.pop_back();
if (IntermediateVisited.count(R))
continue;
IntermediateVisited.insert(R);
if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
if (SymReaper.isLive(Loc, VR))
WorkList.push_back(std::make_pair(store, VR));
continue;
}
if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) {
llvm::SmallVectorImpl<RBDNode> &Q =
llvm::SmallVectorImpl<RBDNode> &Q =
SymReaper.isLive(SR->getSymbol()) ? WorkList : Postponed;
Q.push_back(std::make_pair(store, SR));
continue;
}
// Add the super region for R to the worklist if it is a subregion.
if (const SubRegion* superR =
dyn_cast<SubRegion>(cast<SubRegion>(R)->getSuperRegion()))
@ -1765,14 +1765,14 @@ Store RegionStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
WorkList.push_back(std::make_pair(store, *I));
}
RegionRoots.clear();
llvm::DenseSet<RBDNode> Visited;
tryAgain:
while (!WorkList.empty()) {
RBDNode N = WorkList.back();
WorkList.pop_back();
// Have we visited this node before?
if (Visited.count(N))
continue;
@ -1780,10 +1780,10 @@ tryAgain:
const MemRegion *R = N.second;
Store store_N = N.first;
// Enqueue subregions.
RegionStoreSubRegionMap *M;
if (store == store_N)
M = SubRegions.get();
else {
@ -1805,7 +1805,7 @@ tryAgain:
// If 'R' is a field or an element, we want to keep the bindings
// for the other fields and elements around. The reason is that
// pointer arithmetic can get us to the other fields or elements.
assert(isa<FieldRegion>(R) || isa<ElementRegion>(R)
assert(isa<FieldRegion>(R) || isa<ElementRegion>(R)
|| isa<ObjCIvarRegion>(R));
WorkList.push_back(std::make_pair(store_N, superR));
}
@ -1815,7 +1815,7 @@ tryAgain:
// should continue to track that symbol.
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
SymReaper.markLive(SymR->getSymbol());
// For BlockDataRegions, enqueue the VarRegions for variables marked
// with __block (passed-by-reference).
// via BlockDeclRefExprs.
@ -1832,7 +1832,7 @@ tryAgain:
}
RegionBindings B_N = GetRegionBindings(store_N);
// Get the data binding for R (if any).
Optional<SVal> V = getBinding(B_N, R);
@ -1840,7 +1840,7 @@ tryAgain:
// Check for lazy bindings.
if (const nonloc::LazyCompoundVal *LCV =
dyn_cast<nonloc::LazyCompoundVal>(V.getPointer())) {
const LazyCompoundValData *D = LCV->getCVData();
WorkList.push_back(std::make_pair(D->getStore(), D->getRegion()));
}
@ -1849,18 +1849,18 @@ tryAgain:
for (SVal::symbol_iterator SI=V->symbol_begin(), SE=V->symbol_end();
SI!=SE;++SI)
SymReaper.markLive(*SI);
// If V is a region, then add it to the worklist.
if (const MemRegion *RX = V->getAsRegion())
WorkList.push_back(std::make_pair(store_N, RX));
}
}
}
// See if any postponed SymbolicRegions are actually live now, after
// having done a scan.
for (llvm::SmallVectorImpl<RBDNode>::iterator I = Postponed.begin(),
E = Postponed.end() ; I != E ; ++I) {
E = Postponed.end() ; I != E ; ++I) {
if (const SymbolicRegion *SR = cast_or_null<SymbolicRegion>(I->second)) {
if (SymReaper.isLive(SR->getSymbol())) {
WorkList.push_back(*I);
@ -1868,10 +1868,10 @@ tryAgain:
}
}
}
if (!WorkList.empty())
goto tryAgain;
// We have now scanned the store, marking reachable regions and symbols
// as live. We now remove all the regions that are dead from the store
// as well as update DSymbols with the set symbols that are now dead.