forked from OSchip/llvm-project
[analyzer] Cache offset computation for MemRegion
Achieves almost a 200% speedup on the example where the performance of visitors was problematic. Performance on sqlite3 is unaffected. rdar://38818362 Differential Revision: https://reviews.llvm.org/D45113 llvm-svn: 328911
This commit is contained in:
parent
137ca91f52
commit
fa4d18c7e3
|
@ -86,6 +86,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Kind kind;
|
const Kind kind;
|
||||||
|
mutable Optional<RegionOffset> cachedOffset;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MemRegion(Kind k) : kind(k) {}
|
MemRegion(Kind k) : kind(k) {}
|
||||||
|
|
|
@ -1259,47 +1259,46 @@ static bool isImmediateBase(const CXXRecordDecl *Child,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegionOffset MemRegion::getAsOffset() const {
|
static RegionOffset calculateOffset(const MemRegion *R) {
|
||||||
const MemRegion *R = this;
|
|
||||||
const MemRegion *SymbolicOffsetBase = nullptr;
|
const MemRegion *SymbolicOffsetBase = nullptr;
|
||||||
int64_t Offset = 0;
|
int64_t Offset = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
switch (R->getKind()) {
|
switch (R->getKind()) {
|
||||||
case CodeSpaceRegionKind:
|
case MemRegion::CodeSpaceRegionKind:
|
||||||
case StackLocalsSpaceRegionKind:
|
case MemRegion::StackLocalsSpaceRegionKind:
|
||||||
case StackArgumentsSpaceRegionKind:
|
case MemRegion::StackArgumentsSpaceRegionKind:
|
||||||
case HeapSpaceRegionKind:
|
case MemRegion::HeapSpaceRegionKind:
|
||||||
case UnknownSpaceRegionKind:
|
case MemRegion::UnknownSpaceRegionKind:
|
||||||
case StaticGlobalSpaceRegionKind:
|
case MemRegion::StaticGlobalSpaceRegionKind:
|
||||||
case GlobalInternalSpaceRegionKind:
|
case MemRegion::GlobalInternalSpaceRegionKind:
|
||||||
case GlobalSystemSpaceRegionKind:
|
case MemRegion::GlobalSystemSpaceRegionKind:
|
||||||
case GlobalImmutableSpaceRegionKind:
|
case MemRegion::GlobalImmutableSpaceRegionKind:
|
||||||
// Stores can bind directly to a region space to set a default value.
|
// Stores can bind directly to a region space to set a default value.
|
||||||
assert(Offset == 0 && !SymbolicOffsetBase);
|
assert(Offset == 0 && !SymbolicOffsetBase);
|
||||||
goto Finish;
|
goto Finish;
|
||||||
|
|
||||||
case FunctionCodeRegionKind:
|
case MemRegion::FunctionCodeRegionKind:
|
||||||
case BlockCodeRegionKind:
|
case MemRegion::BlockCodeRegionKind:
|
||||||
case BlockDataRegionKind:
|
case MemRegion::BlockDataRegionKind:
|
||||||
// These will never have bindings, but may end up having values requested
|
// These will never have bindings, but may end up having values requested
|
||||||
// if the user does some strange casting.
|
// if the user does some strange casting.
|
||||||
if (Offset != 0)
|
if (Offset != 0)
|
||||||
SymbolicOffsetBase = R;
|
SymbolicOffsetBase = R;
|
||||||
goto Finish;
|
goto Finish;
|
||||||
|
|
||||||
case SymbolicRegionKind:
|
case MemRegion::SymbolicRegionKind:
|
||||||
case AllocaRegionKind:
|
case MemRegion::AllocaRegionKind:
|
||||||
case CompoundLiteralRegionKind:
|
case MemRegion::CompoundLiteralRegionKind:
|
||||||
case CXXThisRegionKind:
|
case MemRegion::CXXThisRegionKind:
|
||||||
case StringRegionKind:
|
case MemRegion::StringRegionKind:
|
||||||
case ObjCStringRegionKind:
|
case MemRegion::ObjCStringRegionKind:
|
||||||
case VarRegionKind:
|
case MemRegion::VarRegionKind:
|
||||||
case CXXTempObjectRegionKind:
|
case MemRegion::CXXTempObjectRegionKind:
|
||||||
// Usual base regions.
|
// Usual base regions.
|
||||||
goto Finish;
|
goto Finish;
|
||||||
|
|
||||||
case ObjCIvarRegionKind:
|
case MemRegion::ObjCIvarRegionKind:
|
||||||
// This is a little strange, but it's a compromise between
|
// This is a little strange, but it's a compromise between
|
||||||
// ObjCIvarRegions having unknown compile-time offsets (when using the
|
// ObjCIvarRegions having unknown compile-time offsets (when using the
|
||||||
// non-fragile runtime) and yet still being distinct, non-overlapping
|
// non-fragile runtime) and yet still being distinct, non-overlapping
|
||||||
|
@ -1307,14 +1306,14 @@ RegionOffset MemRegion::getAsOffset() const {
|
||||||
// of computing offsets.
|
// of computing offsets.
|
||||||
goto Finish;
|
goto Finish;
|
||||||
|
|
||||||
case CXXBaseObjectRegionKind: {
|
case MemRegion::CXXBaseObjectRegionKind: {
|
||||||
const CXXBaseObjectRegion *BOR = cast<CXXBaseObjectRegion>(R);
|
const CXXBaseObjectRegion *BOR = cast<CXXBaseObjectRegion>(R);
|
||||||
R = BOR->getSuperRegion();
|
R = BOR->getSuperRegion();
|
||||||
|
|
||||||
QualType Ty;
|
QualType Ty;
|
||||||
bool RootIsSymbolic = false;
|
bool RootIsSymbolic = false;
|
||||||
if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(R)) {
|
if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(R)) {
|
||||||
Ty = TVR->getDesugaredValueType(getContext());
|
Ty = TVR->getDesugaredValueType(R->getContext());
|
||||||
} else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
|
} else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
|
||||||
// If our base region is symbolic, we don't know what type it really is.
|
// If our base region is symbolic, we don't know what type it really is.
|
||||||
// Pretend the type of the symbol is the true dynamic type.
|
// Pretend the type of the symbol is the true dynamic type.
|
||||||
|
@ -1348,17 +1347,17 @@ RegionOffset MemRegion::getAsOffset() const {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
CharUnits BaseOffset;
|
CharUnits BaseOffset;
|
||||||
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Child);
|
const ASTRecordLayout &Layout = R->getContext().getASTRecordLayout(Child);
|
||||||
if (BOR->isVirtual())
|
if (BOR->isVirtual())
|
||||||
BaseOffset = Layout.getVBaseClassOffset(BOR->getDecl());
|
BaseOffset = Layout.getVBaseClassOffset(BOR->getDecl());
|
||||||
else
|
else
|
||||||
BaseOffset = Layout.getBaseClassOffset(BOR->getDecl());
|
BaseOffset = Layout.getBaseClassOffset(BOR->getDecl());
|
||||||
|
|
||||||
// The base offset is in chars, not in bits.
|
// The base offset is in chars, not in bits.
|
||||||
Offset += BaseOffset.getQuantity() * getContext().getCharWidth();
|
Offset += BaseOffset.getQuantity() * R->getContext().getCharWidth();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ElementRegionKind: {
|
case MemRegion::ElementRegionKind: {
|
||||||
const ElementRegion *ER = cast<ElementRegion>(R);
|
const ElementRegion *ER = cast<ElementRegion>(R);
|
||||||
R = ER->getSuperRegion();
|
R = ER->getSuperRegion();
|
||||||
|
|
||||||
|
@ -1379,14 +1378,14 @@ RegionOffset MemRegion::getAsOffset() const {
|
||||||
|
|
||||||
int64_t i = CI->getValue().getSExtValue();
|
int64_t i = CI->getValue().getSExtValue();
|
||||||
// This type size is in bits.
|
// This type size is in bits.
|
||||||
Offset += i * getContext().getTypeSize(EleTy);
|
Offset += i * R->getContext().getTypeSize(EleTy);
|
||||||
} else {
|
} else {
|
||||||
// We cannot compute offset for non-concrete index.
|
// We cannot compute offset for non-concrete index.
|
||||||
SymbolicOffsetBase = R;
|
SymbolicOffsetBase = R;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FieldRegionKind: {
|
case MemRegion::FieldRegionKind: {
|
||||||
const FieldRegion *FR = cast<FieldRegion>(R);
|
const FieldRegion *FR = cast<FieldRegion>(R);
|
||||||
R = FR->getSuperRegion();
|
R = FR->getSuperRegion();
|
||||||
|
|
||||||
|
@ -1412,7 +1411,7 @@ RegionOffset MemRegion::getAsOffset() const {
|
||||||
if (FR->getDecl() == *FI)
|
if (FR->getDecl() == *FI)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
|
const ASTRecordLayout &Layout = R->getContext().getASTRecordLayout(RD);
|
||||||
// This is offset in bits.
|
// This is offset in bits.
|
||||||
Offset += Layout.getFieldOffset(idx);
|
Offset += Layout.getFieldOffset(idx);
|
||||||
break;
|
break;
|
||||||
|
@ -1426,6 +1425,12 @@ RegionOffset MemRegion::getAsOffset() const {
|
||||||
return RegionOffset(R, Offset);
|
return RegionOffset(R, Offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RegionOffset MemRegion::getAsOffset() const {
|
||||||
|
if (!cachedOffset)
|
||||||
|
cachedOffset = calculateOffset(this);
|
||||||
|
return *cachedOffset;
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// BlockDataRegion
|
// BlockDataRegion
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
Loading…
Reference in New Issue