steakhal updated this revision to Diff 281556.
steakhal marked 3 inline comments as done.
steakhal added a comment.

Reworked `ElementRegion` handling.
Previously it handled only element regions in the form of: `Element{X,n} OP 
Element{X,m}`
Now supports `Element{X,n} OP X` and `X OP Element{X,n}` as well.
Still misses nested ElementRegions though like: `Element{X,n} OP 
Element{Element{X,k},m}`.

No tests yet.
Regression test vs unit test - which should I prefer?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84736/new/

https://reviews.llvm.org/D84736

Files:
  clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp

Index: clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -1017,40 +1017,77 @@
       }
     }
 
-    // Handle special cases for when both regions are element regions.
-    const ElementRegion *RightER = dyn_cast<ElementRegion>(RightMR);
-    const ElementRegion *LeftER = dyn_cast<ElementRegion>(LeftMR);
-    if (RightER && LeftER) {
-      // Next, see if the two ERs have the same super-region and matching types.
-      // FIXME: This should do something useful even if the types don't match,
-      // though if both indexes are constant the RegionRawOffset path will
-      // give the correct answer.
-      if (LeftER->getSuperRegion() == RightER->getSuperRegion() &&
-          LeftER->getElementType() == RightER->getElementType()) {
-        // Get the left index and cast it to the correct type.
-        // If the index is unknown or undefined, bail out here.
-        SVal LeftIndexVal = LeftER->getIndex();
-        Optional<NonLoc> LeftIndex = LeftIndexVal.getAs<NonLoc>();
-        if (!LeftIndex)
-          return UnknownVal();
-        LeftIndexVal = evalCastFromNonLoc(*LeftIndex, ArrayIndexTy);
-        LeftIndex = LeftIndexVal.getAs<NonLoc>();
-        if (!LeftIndex)
+    // Handle: \forall MemRegion X, \forall NonLoc n, m:
+    //  - Element{X,n} OP Element{X,m}
+    //  - Element{X,n} OP X
+    //  -            X OP Element{X,n}
+    // We don't handle here nested ElementRegions like in the this expression:
+    // Element{Element{x,3,int [10]},5,int}  ==  Element{x,35,int}
+    {
+      // Calculates the byte offset within the memory region to the referred
+      // element.
+      const auto ByteOffsetOfElement =
+          [this, state](const ElementRegion *ElemReg) -> NonLoc {
+        NonLoc Index = evalCastFromNonLoc(ElemReg->getIndex(), ArrayIndexTy)
+                           .castAs<NonLoc>();
+        CharUnits SingleElementSize =
+            ElemReg->getContext().getTypeSizeInChars(ElemReg->getElementType());
+        return evalBinOpNN(state, BO_Mul, Index,
+                           makeArrayIndex(SingleElementSize.getQuantity()),
+                           ArrayIndexTy)
+            .castAs<NonLoc>();
+      };
+
+      // If both has the same memory region, and the index has a concrete value,
+      // we can evaluate equality operators.
+      const auto EvaluateEqualityOperators =
+          [this, state, op, resultTy](NonLoc Index,
+                                      bool HasSameMemRegions) -> SVal {
+        assert(BinaryOperator::isEqualityOp(op));
+        const llvm::APSInt *Int = getKnownValue(state, Index);
+        if (!Int)
           return UnknownVal();
 
-        // Do the same for the right index.
-        SVal RightIndexVal = RightER->getIndex();
-        Optional<NonLoc> RightIndex = RightIndexVal.getAs<NonLoc>();
-        if (!RightIndex)
-          return UnknownVal();
-        RightIndexVal = evalCastFromNonLoc(*RightIndex, ArrayIndexTy);
-        RightIndex = RightIndexVal.getAs<NonLoc>();
-        if (!RightIndex)
-          return UnknownVal();
+        const bool EQResult = HasSameMemRegions && *Int == 0;
+        return makeTruthVal(op == BO_EQ ? EQResult : !EQResult, resultTy);
+      };
+
+      const ElementRegion *RightER = dyn_cast<ElementRegion>(RightMR);
+      const ElementRegion *LeftER = dyn_cast<ElementRegion>(LeftMR);
+      if (RightER && LeftER) {
+        // Next, see if the two ERs have the same super-region and matching
+        // types.
+        // FIXME: This should do something useful even if the types don't match,
+        // though if both indexes are constant the RegionRawOffset path will
+        // give the correct answer.
+        if (LeftER->getSuperRegion() == RightER->getSuperRegion() &&
+            LeftER->getElementType() == RightER->getElementType()) {
+          return evalBinOpNN(state, op, ByteOffsetOfElement(LeftER),
+                             ByteOffsetOfElement(RightER), resultTy);
+        }
+      } else if (LeftER && !RightER) {
+        NonLoc LeftIndex = ByteOffsetOfElement(LeftER);
+        const bool HasSameMemRegions = LeftER->getSuperRegion() == RightMR;
 
-        // Actually perform the operation.
-        // evalBinOpNN expects the two indexes to already be the right type.
-        return evalBinOpNN(state, op, *LeftIndex, *RightIndex, resultTy);
+        if (BinaryOperator::isEqualityOp(op))
+          return EvaluateEqualityOperators(LeftIndex, HasSameMemRegions);
+
+        if (op == BO_Sub && HasSameMemRegions)
+          return LeftIndex;
+        return UnknownVal();
+      } else if (!LeftER && RightER) {
+        NonLoc RightIndex = ByteOffsetOfElement(RightER);
+        const bool HasSameMemRegions = LeftMR == RightER->getSuperRegion();
+
+        if (BinaryOperator::isEqualityOp(op))
+          return EvaluateEqualityOperators(RightIndex, HasSameMemRegions);
+
+        // FIXME: Consider refactoring evalMinus function to accept the State
+        // as well, and use it here.
+        if (op == BO_Sub && HasSameMemRegions)
+          return evalBinOpNN(state, BO_Sub, makeZeroArrayIndex(), RightIndex,
+                             ArrayIndexTy);
+        return UnknownVal();
       }
     }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to