From: Jordan Rose Date: Thu, 9 Aug 2012 22:55:37 +0000 (+0000) Subject: [analyzer] Cache the "concrete offset base" for regions with symbolic offsets. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=824e07ac8f5c9efdddb4254de0203b9675b1ef0b;p=clang [analyzer] Cache the "concrete offset base" for regions with symbolic offsets. This makes it faster to access and invalidate bindings with symbolic offsets by only computing this information once. No intended functionality change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161635 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 2018bd2e44..1281cfbda9 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -52,11 +52,19 @@ class RegionOffset { int64_t Offset; public: + enum { Symbolic = INT64_MAX }; + RegionOffset() : R(0) {} RegionOffset(const MemRegion *r, int64_t off) : R(r), Offset(off) {} const MemRegion *getRegion() const { return R; } - int64_t getOffset() const { return Offset; } + + bool hasSymbolicOffset() const { return Offset == Symbolic; } + + int64_t getOffset() const { + assert(!hasSymbolicOffset()); + return Offset; + } bool isValid() const { return R; } }; diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index b2e7055c31..58abc9a280 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -1038,12 +1038,14 @@ RegionRawOffset ElementRegion::getAsArrayOffset() const { RegionOffset MemRegion::getAsOffset() const { const MemRegion *R = this; + const MemRegion *SymbolicOffsetBase = 0; int64_t Offset = 0; while (1) { switch (R->getKind()) { default: - return RegionOffset(); + return RegionOffset(R, RegionOffset::Symbolic); + case SymbolicRegionKind: case AllocaRegionKind: case CompoundLiteralRegionKind: @@ -1053,6 +1055,7 @@ RegionOffset MemRegion::getAsOffset() const { case ObjCIvarRegionKind: case CXXTempObjectRegionKind: goto Finish; + case CXXBaseObjectRegionKind: { const CXXBaseObjectRegion *BOR = cast(R); R = BOR->getSuperRegion(); @@ -1070,8 +1073,14 @@ RegionOffset MemRegion::getAsOffset() const { const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl(); if (!Child) { // We cannot compute the offset of the base class. - return RegionOffset(); + SymbolicOffsetBase = R; } + + // Don't bother calculating precise offsets if we already have a + // symbolic offset somewhere in the chain. + if (SymbolicOffsetBase) + continue; + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Child); CharUnits BaseOffset; @@ -1087,29 +1096,46 @@ RegionOffset MemRegion::getAsOffset() const { } case ElementRegionKind: { const ElementRegion *ER = cast(R); - QualType EleTy = ER->getValueType(); + R = ER->getSuperRegion(); - if (!IsCompleteType(getContext(), EleTy)) - return RegionOffset(); + QualType EleTy = ER->getValueType(); + if (!IsCompleteType(getContext(), EleTy)) { + // We cannot compute the offset of the base class. + SymbolicOffsetBase = R; + continue; + } SVal Index = ER->getIndex(); if (const nonloc::ConcreteInt *CI=dyn_cast(&Index)) { + // Don't bother calculating precise offsets if we already have a + // symbolic offset somewhere in the chain. + if (SymbolicOffsetBase) + continue; + int64_t i = CI->getValue().getSExtValue(); // This type size is in bits. Offset += i * getContext().getTypeSize(EleTy); } else { // We cannot compute offset for non-concrete index. - return RegionOffset(); + SymbolicOffsetBase = R; } - R = ER->getSuperRegion(); break; } case FieldRegionKind: { const FieldRegion *FR = cast(R); + R = FR->getSuperRegion(); + const RecordDecl *RD = FR->getDecl()->getParent(); - if (!RD->isCompleteDefinition()) + if (!RD->isCompleteDefinition()) { // We cannot compute offset for incomplete type. - return RegionOffset(); + SymbolicOffsetBase = R; + } + + // Don't bother calculating precise offsets if we already have a + // symbolic offset somewhere in the chain. + if (SymbolicOffsetBase) + continue; + // Get the field number. unsigned idx = 0; for (RecordDecl::field_iterator FI = RD->field_begin(), @@ -1120,13 +1146,14 @@ RegionOffset MemRegion::getAsOffset() const { const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); // This is offset in bits. Offset += Layout.getFieldOffset(idx); - R = FR->getSuperRegion(); break; } } } Finish: + if (SymbolicOffsetBase) + return RegionOffset(SymbolicOffsetBase, RegionOffset::Symbolic); return RegionOffset(R, Offset); } diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index 90bd0f31a5..1ba46ea067 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -40,33 +40,42 @@ using llvm::Optional; namespace { class BindingKey { public: - enum Kind { Direct = 0x0, Default = 0x1 }; + enum Kind { Default = 0x0, Direct = 0x1 }; private: - enum { SYMBOLIC = UINT64_MAX }; + enum { Symbolic = 0x2 }; - llvm::PointerIntPair P; - uint64_t Offset; + llvm::PointerIntPair P; + uint64_t Data; - explicit BindingKey(const MemRegion *r, Kind k) - : P(r, k), Offset(SYMBOLIC) {} + explicit BindingKey(const MemRegion *r, const MemRegion *Base, Kind k) + : P(r, k | Symbolic), Data(reinterpret_cast(Base)) { + assert(r && Base && "Must have known regions."); + assert(getConcreteOffsetRegion() == Base && "Failed to store base region"); + } explicit BindingKey(const MemRegion *r, uint64_t offset, Kind k) - : P(r, k), Offset(offset) {} + : P(r, k), Data(offset) { + assert(r && "Must have known regions."); + assert(getOffset() == offset && "Failed to store offset"); + } public: - bool isDirect() const { return P.getInt() == Direct; } - bool hasSymbolicOffset() const { return Offset == SYMBOLIC; } + bool isDirect() const { return P.getInt() & Direct; } + bool hasSymbolicOffset() const { return P.getInt() & Symbolic; } const MemRegion *getRegion() const { return P.getPointer(); } uint64_t getOffset() const { assert(!hasSymbolicOffset()); - return Offset; + return Data; } - const MemRegion *getConcreteOffsetRegion() const; + const MemRegion *getConcreteOffsetRegion() const { + assert(hasSymbolicOffset()); + return reinterpret_cast(static_cast(Data)); + } void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddPointer(P.getOpaqueValue()); - ID.AddInteger(Offset); + ID.AddInteger(Data); } static BindingKey Make(const MemRegion *R, Kind k); @@ -76,12 +85,12 @@ public: return true; if (P.getOpaqueValue() > X.P.getOpaqueValue()) return false; - return Offset < X.Offset; + return Data < X.Data; } bool operator==(const BindingKey &X) const { return P.getOpaqueValue() == X.P.getOpaqueValue() && - Offset == X.Offset; + Data == X.Data; } bool isValid() const { @@ -92,27 +101,10 @@ public: BindingKey BindingKey::Make(const MemRegion *R, Kind k) { const RegionOffset &RO = R->getAsOffset(); - if (RO.isValid()) - return BindingKey(RO.getRegion(), RO.getOffset(), k); - - return BindingKey(R, k); -} - -const MemRegion *BindingKey::getConcreteOffsetRegion() const { - const MemRegion *R = getRegion(); - if (!hasSymbolicOffset()) - return R; - - RegionOffset RO; - do { - const SubRegion *SR = dyn_cast(R); - if (!SR) - break; - R = SR->getSuperRegion(); - RO = R->getAsOffset(); - } while (!RO.isValid()); + if (RO.hasSymbolicOffset()) + return BindingKey(R, RO.getRegion(), k); - return R; + return BindingKey(RO.getRegion(), RO.getOffset(), k); } namespace llvm { @@ -561,7 +553,6 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B, // by changing the data structure used for RegionBindings. BindingKey SRKey = BindingKey::Make(R, BindingKey::Default); - assert(SRKey.isValid()); if (SRKey.hasSymbolicOffset()) { const SubRegion *Base = cast(SRKey.getConcreteOffsetRegion()); B = removeSubRegionBindings(B, Base);