]> granicus.if.org Git - clang/commitdiff
[analyzer] Cache the "concrete offset base" for regions with symbolic offsets.
authorJordan Rose <jordan_rose@apple.com>
Thu, 9 Aug 2012 22:55:37 +0000 (22:55 +0000)
committerJordan Rose <jordan_rose@apple.com>
Thu, 9 Aug 2012 22:55:37 +0000 (22:55 +0000)
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

include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
lib/StaticAnalyzer/Core/MemRegion.cpp
lib/StaticAnalyzer/Core/RegionStore.cpp

index 2018bd2e44cdf88064fdf0fd2f4d8c338a5cada1..1281cfbda93ca29e308a61ae681e33756b3c625b 100644 (file)
@@ -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; }
 };
index b2e7055c313dfd5343bcef7b5d82aae4b024e834..58abc9a2809cc32e80f2eb98bd0fc11ebadeacee 100644 (file)
@@ -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<CXXBaseObjectRegion>(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<ElementRegion>(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<nonloc::ConcreteInt>(&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<FieldRegion>(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);
 }
 
index 90bd0f31a5104bd525cb10070fd1e8d55d90e999..1ba46ea067523182da0e8e002843fcc215a562fd 100644 (file)
@@ -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<const MemRegion *, 1, Kind> P;
-  uint64_t Offset;
+  llvm::PointerIntPair<const MemRegion *, 2> 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<uintptr_t>(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<const MemRegion *>(static_cast<uintptr_t>(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<SubRegion>(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<SubRegion>(SRKey.getConcreteOffsetRegion());
     B = removeSubRegionBindings(B, Base);