[clang][dataflow] Merge distinct pointer values in Environment::join
authorStanislav Gatev <sgatev@google.com>
Fri, 28 Jan 2022 16:23:01 +0000 (16:23 +0000)
committerStanislav Gatev <sgatev@google.com>
Sat, 29 Jan 2022 16:33:15 +0000 (16:33 +0000)
This is part of the implementation of the dataflow analysis framework.
See "[RFC] A dataflow analysis framework for Clang AST" on cfe-dev.

Reviewed-by: ymandel, xazax.hun
Differential Revision: https://reviews.llvm.org/D118480

clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp

index 938f733..8392f95 100644 (file)
@@ -89,8 +89,12 @@ LatticeJoinEffect Environment::join(const Environment &Other,
   if (ExprToLocSizeBefore != ExprToLoc.size())
     Effect = LatticeJoinEffect::Changed;
 
-  llvm::DenseMap<const StorageLocation *, Value *> MergedLocToVal;
-  for (auto &Entry : LocToVal) {
+  // Move `LocToVal` so that `Environment::Merger::merge` can safely assign
+  // values to storage locations while this code iterates over the current
+  // assignments.
+  llvm::DenseMap<const StorageLocation *, Value *> OldLocToVal =
+      std::move(LocToVal);
+  for (auto &Entry : OldLocToVal) {
     const StorageLocation *Loc = Entry.first;
     assert(Loc != nullptr);
 
@@ -103,19 +107,25 @@ LatticeJoinEffect Environment::join(const Environment &Other,
     assert(It->second != nullptr);
 
     if (It->second == Val) {
-      MergedLocToVal.insert({Loc, Val});
+      LocToVal.insert({Loc, Val});
       continue;
     }
 
+    if (auto *FirstVal = dyn_cast<PointerValue>(Val)) {
+      auto *SecondVal = cast<PointerValue>(It->second);
+      if (&FirstVal->getPointeeLoc() == &SecondVal->getPointeeLoc()) {
+        LocToVal.insert({Loc, FirstVal});
+        continue;
+      }
+    }
+
     // FIXME: Consider destroying `MergedValue` immediately if `Merger::merge`
     // returns false to avoid storing unneeded values in `DACtx`.
     if (Value *MergedVal = createValue(Loc->getType()))
       if (Merger.merge(Loc->getType(), *Val, *It->second, *MergedVal, *this))
-        MergedLocToVal.insert({Loc, MergedVal});
+        LocToVal.insert({Loc, MergedVal});
   }
-  const unsigned LocToValSizeBefore = LocToVal.size();
-  LocToVal = std::move(MergedLocToVal);
-  if (LocToValSizeBefore != LocToVal.size())
+  if (OldLocToVal.size() != LocToVal.size())
     Effect = LatticeJoinEffect::Changed;
 
   return Effect;
index ee0bc3e..e9d5e12 100644 (file)
@@ -494,4 +494,37 @@ TEST_F(WideningTest, JoinDistinctValuesWithSameProperties) {
       });
 }
 
+TEST_F(WideningTest, DistinctPointersToTheSameLocation) {
+  std::string Code = R"(
+    void target(int Foo, bool Cond) {
+      int *Bar = &Foo;
+      while (Cond) {
+        Bar = &Foo;
+      }
+      (void)0;
+      // [[p]]
+    }
+  )";
+  runDataflow(Code,
+              [](llvm::ArrayRef<
+                     std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
+                     Results,
+                 ASTContext &ASTCtx) {
+                ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
+                const Environment &Env = Results[0].second.Env;
+
+                const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
+                ASSERT_THAT(FooDecl, NotNull());
+
+                const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
+                ASSERT_THAT(BarDecl, NotNull());
+
+                const auto *FooLoc = cast<ScalarStorageLocation>(
+                    Env.getStorageLocation(*FooDecl, SkipPast::None));
+                const auto *BarVal =
+                    cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
+                EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc);
+              });
+}
+
 } // namespace