<div dir="ltr">Reverted in r332674, since I don't believe the person who LGTMed this review has appropriate context on this code. I apologize if I'm wrong. I'll comment on the review thread shortly.</div><br><div class="gmail_quote"><div dir="ltr">On Thu, May 17, 2018 at 1:27 PM David Bolvansky via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: xbolva00<br>
Date: Thu May 17 13:23:33 2018<br>
New Revision: 332657<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=332657&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=332657&view=rev</a><br>
Log:<br>
[AA] cfl-anders-aa with field sensitivity<br>
<br>
Summary:<br>
There was some unfinished work started for offset tracking in CFLGraph by the author of implementation of Andersen algorithm. This work was completed and support for field sensitivity was added to the core of Andersen algorithm.<br>
<br>
The performance results seem promising.<br>
<br>
SPEC2006 int_base score was increased by 1.1 % (I  compared clang 6.0 with clang 6.0 with this patch). The avergae compile time was increased by +- 1 % according my measures with small and medium C/C++ projects (I did not tested it on the large projects with milions of lines of code)<br>
<br>
Reviewers: chandlerc, george.burgess.iv, rja<br>
<br>
Reviewed By: rja<br>
<br>
Subscribers: rja, llvm-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D46282" rel="noreferrer" target="_blank">https://reviews.llvm.org/D46282</a><br>
<br>
Added:<br>
    llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/field.ll<br>
Modified:<br>
    llvm/trunk/lib/Analysis/AliasAnalysisSummary.h<br>
    llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp<br>
    llvm/trunk/lib/Analysis/CFLGraph.h<br>
<br>
Modified: llvm/trunk/lib/Analysis/AliasAnalysisSummary.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/AliasAnalysisSummary.h?rev=332657&r1=332656&r2=332657&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/AliasAnalysisSummary.h?rev=332657&r1=332656&r2=332657&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Analysis/AliasAnalysisSummary.h (original)<br>
+++ llvm/trunk/lib/Analysis/AliasAnalysisSummary.h Thu May 17 13:23:33 2018<br>
@@ -134,18 +134,31 @@ inline bool operator>=(InterfaceValue LH<br>
   return !(LHS < RHS);<br>
 }<br>
<br>
+using FieldOffset = int64_t;<br>
 // We use UnknownOffset to represent pointer offsets that cannot be determined<br>
 // at compile time. Note that MemoryLocation::UnknownSize cannot be used here<br>
 // because we require a signed value.<br>
-static const int64_t UnknownOffset = INT64_MAX;<br>
+static const FieldOffset UnknownOffset =<br>
+    std::numeric_limits<FieldOffset>::max();<br>
<br>
-inline int64_t addOffset(int64_t LHS, int64_t RHS) {<br>
+inline FieldOffset addFieldOffset(FieldOffset LHS, FieldOffset RHS) {<br>
   if (LHS == UnknownOffset || RHS == UnknownOffset)<br>
     return UnknownOffset;<br>
-  // FIXME: Do we need to guard against integer overflow here?<br>
+<br>
   return LHS + RHS;<br>
 }<br>
<br>
+inline FieldOffset subFieldOffset(FieldOffset LHS, FieldOffset RHS) {<br>
+  if (LHS == UnknownOffset || RHS == UnknownOffset)<br>
+    return UnknownOffset;<br>
+<br>
+  return LHS - RHS;<br>
+}<br>
+<br>
+inline FieldOffset negFieldOffset(FieldOffset Offset) {<br>
+  return subFieldOffset(0, Offset);<br>
+}<br>
+<br>
 /// We use ExternalRelation to describe an externally visible aliasing relations<br>
 /// between parameters/return value of a function.<br>
 struct ExternalRelation {<br>
<br>
Modified: llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp?rev=332657&r1=332656&r2=332657&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp?rev=332657&r1=332656&r2=332657&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp (original)<br>
+++ llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp Thu May 17 13:23:33 2018<br>
@@ -153,11 +153,59 @@ struct OffsetInstantiatedValue {<br>
 bool operator==(OffsetInstantiatedValue LHS, OffsetInstantiatedValue RHS) {<br>
   return LHS.IVal == RHS.IVal && LHS.Offset == RHS.Offset;<br>
 }<br>
+}<br>
+<br>
+namespace llvm {<br>
+<br>
+// Specialize DenseMapInfo for OffsetValue.<br>
+template <> struct DenseMapInfo<OffsetValue> {<br>
+  static OffsetValue getEmptyKey() {<br>
+    return OffsetValue{DenseMapInfo<const Value *>::getEmptyKey(),<br>
+                       DenseMapInfo<FieldOffset>::getEmptyKey()};<br>
+  }<br>
+  static OffsetValue getTombstoneKey() {<br>
+    return OffsetValue{DenseMapInfo<const Value *>::getTombstoneKey(),<br>
+                       DenseMapInfo<FieldOffset>::getEmptyKey()};<br>
+  }<br>
+  static unsigned getHashValue(const OffsetValue &OVal) {<br>
+    return DenseMapInfo<std::pair<const Value *, FieldOffset>>::getHashValue(<br>
+        std::make_pair(OVal.Val, OVal.Offset));<br>
+  }<br>
+  static bool isEqual(const OffsetValue &LHS, const OffsetValue &RHS) {<br>
+    return LHS == RHS;<br>
+  }<br>
+};<br>
+<br>
+// Specialize DenseMapInfo for OffsetInstantiatedValue.<br>
+template <> struct DenseMapInfo<OffsetInstantiatedValue> {<br>
+  static OffsetInstantiatedValue getEmptyKey() {<br>
+    return OffsetInstantiatedValue{<br>
+        DenseMapInfo<InstantiatedValue>::getEmptyKey(),<br>
+        DenseMapInfo<FieldOffset>::getEmptyKey()};<br>
+  }<br>
+  static OffsetInstantiatedValue getTombstoneKey() {<br>
+    return OffsetInstantiatedValue{<br>
+        DenseMapInfo<InstantiatedValue>::getTombstoneKey(),<br>
+        DenseMapInfo<FieldOffset>::getEmptyKey()};<br>
+  }<br>
+  static unsigned getHashValue(const OffsetInstantiatedValue &OVal) {<br>
+    return DenseMapInfo<std::pair<InstantiatedValue, FieldOffset>>::<br>
+        getHashValue(std::make_pair(OVal.IVal, OVal.Offset));<br>
+  }<br>
+  static bool isEqual(const OffsetInstantiatedValue &LHS,<br>
+                      const OffsetInstantiatedValue &RHS) {<br>
+    return LHS == RHS;<br>
+  }<br>
+};<br>
+<br>
+} // namespace llvm<br>
+<br>
+namespace {<br>
<br>
 // We use ReachabilitySet to keep track of value aliases (The nonterminal "V" in<br>
 // the paper) during the analysis.<br>
 class ReachabilitySet {<br>
-  using ValueStateMap = DenseMap<InstantiatedValue, StateSet>;<br>
+  using ValueStateMap = DenseMap<OffsetInstantiatedValue, StateSet>;<br>
   using ValueReachMap = DenseMap<InstantiatedValue, ValueStateMap>;<br>
<br>
   ValueReachMap ReachMap;<br>
@@ -166,10 +214,11 @@ public:<br>
   using const_valuestate_iterator = ValueStateMap::const_iterator;<br>
   using const_value_iterator = ValueReachMap::const_iterator;<br>
<br>
-  // Insert edge 'From->To' at state 'State'<br>
-  bool insert(InstantiatedValue From, InstantiatedValue To, MatchState State) {<br>
+  // Insert edge 'From->To' at state 'State' with offset 'Offset'<br>
+  bool insert(InstantiatedValue From, InstantiatedValue To, FieldOffset Offset,<br>
+              MatchState State) {<br>
     assert(From != To);<br>
-    auto &States = ReachMap[To][From];<br>
+    auto &States = ReachMap[To][OffsetInstantiatedValue{From, Offset}];<br>
     auto Idx = static_cast<size_t>(State);<br>
     if (!States.test(Idx)) {<br>
       States.set(Idx);<br>
@@ -254,6 +303,7 @@ public:<br>
 struct WorkListItem {<br>
   InstantiatedValue From;<br>
   InstantiatedValue To;<br>
+  FieldOffset Offset;<br>
   MatchState State;<br>
 };<br>
<br>
@@ -261,63 +311,13 @@ struct ValueSummary {<br>
   struct Record {<br>
     InterfaceValue IValue;<br>
     unsigned DerefLevel;<br>
+    FieldOffset Offset;<br>
   };<br>
   SmallVector<Record, 4> FromRecords, ToRecords;<br>
 };<br>
<br>
 } // end anonymous namespace<br>
<br>
-namespace llvm {<br>
-<br>
-// Specialize DenseMapInfo for OffsetValue.<br>
-template <> struct DenseMapInfo<OffsetValue> {<br>
-  static OffsetValue getEmptyKey() {<br>
-    return OffsetValue{DenseMapInfo<const Value *>::getEmptyKey(),<br>
-                       DenseMapInfo<int64_t>::getEmptyKey()};<br>
-  }<br>
-<br>
-  static OffsetValue getTombstoneKey() {<br>
-    return OffsetValue{DenseMapInfo<const Value *>::getTombstoneKey(),<br>
-                       DenseMapInfo<int64_t>::getEmptyKey()};<br>
-  }<br>
-<br>
-  static unsigned getHashValue(const OffsetValue &OVal) {<br>
-    return DenseMapInfo<std::pair<const Value *, int64_t>>::getHashValue(<br>
-        std::make_pair(OVal.Val, OVal.Offset));<br>
-  }<br>
-<br>
-  static bool isEqual(const OffsetValue &LHS, const OffsetValue &RHS) {<br>
-    return LHS == RHS;<br>
-  }<br>
-};<br>
-<br>
-// Specialize DenseMapInfo for OffsetInstantiatedValue.<br>
-template <> struct DenseMapInfo<OffsetInstantiatedValue> {<br>
-  static OffsetInstantiatedValue getEmptyKey() {<br>
-    return OffsetInstantiatedValue{<br>
-        DenseMapInfo<InstantiatedValue>::getEmptyKey(),<br>
-        DenseMapInfo<int64_t>::getEmptyKey()};<br>
-  }<br>
-<br>
-  static OffsetInstantiatedValue getTombstoneKey() {<br>
-    return OffsetInstantiatedValue{<br>
-        DenseMapInfo<InstantiatedValue>::getTombstoneKey(),<br>
-        DenseMapInfo<int64_t>::getEmptyKey()};<br>
-  }<br>
-<br>
-  static unsigned getHashValue(const OffsetInstantiatedValue &OVal) {<br>
-    return DenseMapInfo<std::pair<InstantiatedValue, int64_t>>::getHashValue(<br>
-        std::make_pair(OVal.IVal, OVal.Offset));<br>
-  }<br>
-<br>
-  static bool isEqual(const OffsetInstantiatedValue &LHS,<br>
-                      const OffsetInstantiatedValue &RHS) {<br>
-    return LHS == RHS;<br>
-  }<br>
-};<br>
-<br>
-} // end namespace llvm<br>
-<br>
 class CFLAndersAAResult::FunctionInfo {<br>
   /// Map a value to other values that may alias it<br>
   /// Since the alias relation is symmetric, to save some space we assume values<br>
@@ -389,9 +389,11 @@ populateAliasMap(DenseMap<const Value *,<br>
     auto Val = OuterMapping.first.Val;<br>
     auto &AliasList = AliasMap[Val];<br>
     for (const auto &InnerMapping : OuterMapping.second) {<br>
+      auto OVal = InnerMapping.first;<br>
       // Again, AliasMap only cares about top-level values<br>
-      if (InnerMapping.first.DerefLevel == 0)<br>
-        AliasList.push_back(OffsetValue{InnerMapping.first.Val, UnknownOffset});<br>
+      if (OVal.IVal.DerefLevel == 0)<br>
+        AliasList.push_back(<br>
+            OffsetValue{OVal.IVal.Val, negFieldOffset(OVal.Offset)});<br>
     }<br>
<br>
     // Sort AliasList for faster lookup<br>
@@ -430,24 +432,27 @@ static void populateExternalRelations(<br>
   for (const auto &OuterMapping : ReachSet.value_mappings()) {<br>
     if (auto Dst = getInterfaceValue(OuterMapping.first, RetVals)) {<br>
       for (const auto &InnerMapping : OuterMapping.second) {<br>
+        auto OVal = InnerMapping.first;<br>
+        auto SrcIVal = OVal.IVal;<br>
+        auto Offset = OVal.Offset;<br>
         // If Src is a param/return value, we get a same-level assignment.<br>
-        if (auto Src = getInterfaceValue(InnerMapping.first, RetVals)) {<br>
+        if (auto Src = getInterfaceValue(SrcIVal, RetVals)) {<br>
           // This may happen if both Dst and Src are return values<br>
           if (*Dst == *Src)<br>
             continue;<br>
<br>
           if (hasReadOnlyState(InnerMapping.second))<br>
-            ExtRelations.push_back(ExternalRelation{*Dst, *Src, UnknownOffset});<br>
+            ExtRelations.push_back(ExternalRelation{*Dst, *Src, Offset});<br>
           // No need to check for WriteOnly state, since ReachSet is symmetric<br>
         } else {<br>
           // If Src is not a param/return, add it to ValueMap<br>
-          auto SrcIVal = InnerMapping.first;<br>
+<br>
           if (hasReadOnlyState(InnerMapping.second))<br>
             ValueMap[SrcIVal.Val].FromRecords.push_back(<br>
-                ValueSummary::Record{*Dst, SrcIVal.DerefLevel});<br>
+                ValueSummary::Record{*Dst, SrcIVal.DerefLevel, Offset});<br>
           if (hasWriteOnlyState(InnerMapping.second))<br>
             ValueMap[SrcIVal.Val].ToRecords.push_back(<br>
-                ValueSummary::Record{*Dst, SrcIVal.DerefLevel});<br>
+                ValueSummary::Record{*Dst, SrcIVal.DerefLevel, Offset});<br>
         }<br>
       }<br>
     }<br>
@@ -466,14 +471,20 @@ static void populateExternalRelations(<br>
         auto SrcLevel = FromRecord.IValue.DerefLevel;<br>
         auto DstIndex = ToRecord.IValue.Index;<br>
         auto DstLevel = ToRecord.IValue.DerefLevel;<br>
+<br>
+        // Offsets to be pushed to External Relations<br>
+        auto SrcOffset = FromRecord.Offset;<br>
+        auto DstOffset = ToRecord.Offset;<br>
+<br>
         if (ToLevel > FromLevel)<br>
           SrcLevel += ToLevel - FromLevel;<br>
         else<br>
           DstLevel += FromLevel - ToLevel;<br>
<br>
-        ExtRelations.push_back(ExternalRelation{<br>
-            InterfaceValue{SrcIndex, SrcLevel},<br>
-            InterfaceValue{DstIndex, DstLevel}, UnknownOffset});<br>
+        ExtRelations.push_back(<br>
+            ExternalRelation{InterfaceValue{SrcIndex, SrcLevel},<br>
+                             InterfaceValue{DstIndex, DstLevel},<br>
+                             subFieldOffset(SrcOffset, DstOffset)});<br>
       }<br>
     }<br>
   }<br>
@@ -591,12 +602,14 @@ bool CFLAndersAAResult::FunctionInfo::ma<br>
 }<br>
<br>
 static void propagate(InstantiatedValue From, InstantiatedValue To,<br>
-                      MatchState State, ReachabilitySet &ReachSet,<br>
+                      FieldOffset Offset, MatchState State,<br>
+                      ReachabilitySet &ReachSet,<br>
                       std::vector<WorkListItem> &WorkList) {<br>
   if (From == To)<br>
     return;<br>
-  if (ReachSet.insert(From, To, State))<br>
-    WorkList.push_back(WorkListItem{From, To, State});<br>
+<br>
+  if (ReachSet.insert(From, To, Offset, State))<br>
+    WorkList.push_back(WorkListItem{From, To, Offset, State});<br>
 }<br>
<br>
 static void initializeWorkList(std::vector<WorkListItem> &WorkList,<br>
@@ -610,13 +623,15 @@ static void initializeWorkList(std::vect<br>
     // Insert all immediate assignment neighbors to the worklist<br>
     for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) {<br>
       auto Src = InstantiatedValue{Val, I};<br>
-      // If there's an assignment edge from X to Y, it means Y is reachable from<br>
-      // X at S2 and X is reachable from Y at S1<br>
+      // If we have an assignment edge from X + Offset to Y, it means that<br>
+      // (Y - Offset) is reachable from X at the state FlowToWriteOnly<br>
+      // At the same time, (X + Offset) is reachable from Y at the state<br>
+      // FlowFromReadOnly<br>
       for (auto &Edge : ValueInfo.getNodeInfoAtLevel(I).Edges) {<br>
-        propagate(Edge.Other, Src, MatchState::FlowFromReadOnly, ReachSet,<br>
-                  WorkList);<br>
-        propagate(Src, Edge.Other, MatchState::FlowToWriteOnly, ReachSet,<br>
-                  WorkList);<br>
+        propagate(Edge.Other, Src, Edge.Offset, MatchState::FlowFromReadOnly,<br>
+                  ReachSet, WorkList);<br>
+        propagate(Src, Edge.Other, negFieldOffset(Edge.Offset),<br>
+                  MatchState::FlowToWriteOnly, ReachSet, WorkList);<br>
       }<br>
     }<br>
   }<br>
@@ -635,37 +650,41 @@ static void processWorkListItem(const Wo<br>
                                 std::vector<WorkListItem> &WorkList) {<br>
   auto FromNode = Item.From;<br>
   auto ToNode = Item.To;<br>
+  auto Offset = Item.Offset;<br>
<br>
   auto NodeInfo = Graph.getNode(ToNode);<br>
   assert(NodeInfo != nullptr);<br>
<br>
-  // TODO: propagate field offsets<br>
-<br>
   // FIXME: Here is a neat trick we can do: since both ReachSet and MemSet holds<br>
   // relations that are symmetric, we could actually cut the storage by half by<br>
   // sorting FromNode and ToNode before insertion happens.<br>
<br>
   // The newly added value alias pair may potentially generate more memory<br>
   // alias pairs. Check for them here.<br>
-  auto FromNodeBelow = getNodeBelow(Graph, FromNode);<br>
-  auto ToNodeBelow = getNodeBelow(Graph, ToNode);<br>
-  if (FromNodeBelow && ToNodeBelow &&<br>
-      MemSet.insert(*FromNodeBelow, *ToNodeBelow)) {<br>
-    propagate(*FromNodeBelow, *ToNodeBelow,<br>
-              MatchState::FlowFromMemAliasNoReadWrite, ReachSet, WorkList);<br>
-    for (const auto &Mapping : ReachSet.reachableValueAliases(*FromNodeBelow)) {<br>
-      auto Src = Mapping.first;<br>
-      auto MemAliasPropagate = [&](MatchState FromState, MatchState ToState) {<br>
-        if (Mapping.second.test(static_cast<size_t>(FromState)))<br>
-          propagate(Src, *ToNodeBelow, ToState, ReachSet, WorkList);<br>
-      };<br>
-<br>
-      MemAliasPropagate(MatchState::FlowFromReadOnly,<br>
-                        MatchState::FlowFromMemAliasReadOnly);<br>
-      MemAliasPropagate(MatchState::FlowToWriteOnly,<br>
-                        MatchState::FlowToMemAliasWriteOnly);<br>
-      MemAliasPropagate(MatchState::FlowToReadWrite,<br>
-                        MatchState::FlowToMemAliasReadWrite);<br>
+  // MemAlias reachability can only be triggered when Offset is 0 or Unknown<br>
+  if (Offset == 0 || Offset == UnknownOffset) {<br>
+    auto FromNodeBelow = getNodeBelow(Graph, FromNode);<br>
+    auto ToNodeBelow = getNodeBelow(Graph, ToNode);<br>
+    if (FromNodeBelow && ToNodeBelow &&<br>
+        MemSet.insert(*FromNodeBelow, *ToNodeBelow)) {<br>
+      propagate(*FromNodeBelow, *ToNodeBelow, Offset,<br>
+                MatchState::FlowFromMemAliasNoReadWrite, ReachSet, WorkList);<br>
+      for (const auto &Mapping :<br>
+           ReachSet.reachableValueAliases(*FromNodeBelow)) {<br>
+        auto SrcOVal = Mapping.first;<br>
+        auto MemAliasPropagate = [&](MatchState FromState, MatchState ToState) {<br>
+          if (Mapping.second.test(static_cast<size_t>(FromState)))<br>
+            propagate(SrcOVal.IVal, *ToNodeBelow, SrcOVal.Offset, ToState,<br>
+                      ReachSet, WorkList);<br>
+        };<br>
+<br>
+        MemAliasPropagate(MatchState::FlowFromReadOnly,<br>
+                          MatchState::FlowFromMemAliasReadOnly);<br>
+        MemAliasPropagate(MatchState::FlowToWriteOnly,<br>
+                          MatchState::FlowToMemAliasWriteOnly);<br>
+        MemAliasPropagate(MatchState::FlowToReadWrite,<br>
+                          MatchState::FlowToMemAliasReadWrite);<br>
+      }<br>
     }<br>
   }<br>
<br>
@@ -678,17 +697,23 @@ static void processWorkListItem(const Wo<br>
   // - If Y is an alias of X, then reverse assignment edges (if there is any)<br>
   // should precede any assignment edges on the path from X to Y.<br>
   auto NextAssignState = [&](MatchState State) {<br>
-    for (const auto &AssignEdge : NodeInfo->Edges)<br>
-      propagate(FromNode, AssignEdge.Other, State, ReachSet, WorkList);<br>
+    for (const auto &AssignEdge : NodeInfo->Edges) {<br>
+      propagate(FromNode, AssignEdge.Other,<br>
+                subFieldOffset(Offset, AssignEdge.Offset), State, ReachSet,<br>
+                WorkList);<br>
+    }<br>
   };<br>
   auto NextRevAssignState = [&](MatchState State) {<br>
-    for (const auto &RevAssignEdge : NodeInfo->ReverseEdges)<br>
-      propagate(FromNode, RevAssignEdge.Other, State, ReachSet, WorkList);<br>
+    for (const auto &RevAssignEdge : NodeInfo->ReverseEdges) {<br>
+      propagate(FromNode, RevAssignEdge.Other,<br>
+                addFieldOffset(Offset, RevAssignEdge.Offset), State, ReachSet,<br>
+                WorkList);<br>
+    }<br>
   };<br>
   auto NextMemState = [&](MatchState State) {<br>
     if (auto AliasSet = MemSet.getMemoryAliases(ToNode)) {<br>
       for (const auto &MemAlias : *AliasSet)<br>
-        propagate(FromNode, MemAlias, State, ReachSet, WorkList);<br>
+        propagate(FromNode, MemAlias, Offset, State, ReachSet, WorkList);<br>
     }<br>
   };<br>
<br>
@@ -753,7 +778,7 @@ static AliasAttrMap buildAttrMap(const C<br>
<br>
       // Propagate attr on the same level<br>
       for (const auto &Mapping : ReachSet.reachableValueAliases(Dst)) {<br>
-        auto Src = Mapping.first;<br>
+        auto Src = Mapping.first.IVal;<br>
         if (AttrMap.add(Src, DstAttr))<br>
           NextList.push_back(Src);<br>
       }<br>
@@ -788,11 +813,19 @@ CFLAndersAAResult::buildInfoFrom(const F<br>
<br>
   std::vector<WorkListItem> WorkList, NextList;<br>
   initializeWorkList(WorkList, ReachSet, Graph);<br>
-  // TODO: make sure we don't stop before the fix point is reached<br>
+<br>
+  bool LoopInGraph = false;<br>
   while (!WorkList.empty()) {<br>
     for (const auto &Item : WorkList)<br>
       processWorkListItem(Item, Graph, ReachSet, MemSet, NextList);<br>
<br>
+    if (NextList.size() == WorkList.size()) {<br>
+      // stop if loop in CFL graph<br>
+      if (LoopInGraph)<br>
+        break;<br>
+      LoopInGraph = true;<br>
+    }<br>
+<br>
     NextList.swap(WorkList);<br>
     NextList.clear();<br>
   }<br>
<br>
Modified: llvm/trunk/lib/Analysis/CFLGraph.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CFLGraph.h?rev=332657&r1=332656&r2=332657&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CFLGraph.h?rev=332657&r1=332656&r2=332657&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Analysis/CFLGraph.h (original)<br>
+++ llvm/trunk/lib/Analysis/CFLGraph.h Thu May 17 13:23:33 2018<br>
@@ -62,7 +62,7 @@ public:<br>
<br>
   struct Edge {<br>
     Node Other;<br>
-    int64_t Offset;<br>
+    FieldOffset Offset;<br>
   };<br>
<br>
   using EdgeList = std::vector<Edge>;<br>
@@ -125,7 +125,7 @@ public:<br>
     Info->Attr |= Attr;<br>
   }<br>
<br>
-  void addEdge(Node From, Node To, int64_t Offset = 0) {<br>
+  void addEdge(Node From, Node To, FieldOffset Offset = 0) {<br>
     auto *FromInfo = getNode(From);<br>
     assert(FromInfo != nullptr);<br>
     auto *ToInfo = getNode(To);<br>
@@ -219,7 +219,7 @@ template <typename CFLAA> class CFLGraph<br>
         Graph.addNode(InstantiatedValue{Val, 0}, Attr);<br>
     }<br>
<br>
-    void addAssignEdge(Value *From, Value *To, int64_t Offset = 0) {<br>
+    void addAssignEdge(Value *From, Value *To, FieldOffset Offset = 0) {<br>
       assert(From != nullptr && To != nullptr);<br>
       if (!From->getType()->isPointerTy() || !To->getType()->isPointerTy())<br>
         return;<br>
@@ -312,7 +312,7 @@ template <typename CFLAA> class CFLGraph<br>
     }<br>
<br>
     void visitGEP(GEPOperator &GEPOp) {<br>
-      uint64_t Offset = UnknownOffset;<br>
+      FieldOffset Offset = UnknownOffset;<br>
       APInt APOffset(DL.getPointerSizeInBits(GEPOp.getPointerAddressSpace()),<br>
                      0);<br>
       if (GEPOp.accumulateConstantOffset(DL, APOffset))<br>
@@ -397,7 +397,7 @@ template <typename CFLAA> class CFLGraph<br>
           if (IRelation.hasValue()) {<br>
             Graph.addNode(IRelation->From);<br>
             Graph.addNode(IRelation->To);<br>
-            Graph.addEdge(IRelation->From, IRelation->To);<br>
+            Graph.addEdge(IRelation->From, IRelation->To, IRelation->Offset);<br>
           }<br>
         }<br>
<br>
<br>
Added: llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/field.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/field.ll?rev=332657&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/field.ll?rev=332657&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/field.ll (added)<br>
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/field.ll Thu May 17 13:23:33 2018<br>
@@ -0,0 +1,102 @@<br>
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py<br>
+; RUN: opt < %s -disable-basicaa -cfl-anders-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s<br>
+; RUN: opt < %s -aa-pipeline=cfl-anders-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s<br>
+<br>
+; CHECK: Function: test_simple_offsets<br>
+; CHECK: NoAlias: i64* %b, i64** %acast<br>
+; CHECK: NoAlias: i64** %acast, i64** %aoff<br>
+; CHECK: NoAlias: i64* %b, i64** %acastoff<br>
+; CHECK: NoAlias: i64** %acast, i64** %acastoff<br>
+; CHECK: NoAlias: [2 x i64*]* %a, i64* %acastload<br>
+; CHECK: MayAlias: i64* %acastload, i64* %b<br>
+; CHECK: NoAlias: i64* %acastload, i64** %aoff<br>
+; CHECK: NoAlias: i64* %acastload, i64** %acast<br>
+; CHECK: NoAlias: i64* %acastload, i64** %acastoff<br>
+define void @test_simple_offsets() {<br>
+  %a = alloca [2 x i64*], align 8<br>
+  %b = alloca i64, align 4<br>
+  %aoff = getelementptr inbounds [2 x i64*], [2 x i64*]* %a, i64 0, i64 1<br>
+  store i64* %b, i64** %aoff<br>
+<br>
+  %acast = bitcast [2 x i64*]* %a to i64**<br>
+  %acastoff = getelementptr inbounds i64*, i64** %acast, i64 1<br>
+  %acastload = load i64*, i64** %acastoff<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK: Function: test_unknown_offset<br>
+; CHECK: MayAlias: [3 x i32]* %a, i32* %an<br>
+; CHECK: MayAlias: i32* %a4, i32* %an<br>
+; CHECK: MayAlias: i32* %a8, i32* %an<br>
+; CHECK: MayAlias: i32* %an, i32* %b<br>
+; CHECK: MayAlias: [3 x i32]* %a, i32* %bn<br>
+; CHECK: MayAlias: i32* %a4, i32* %bn<br>
+; CHECK: MayAlias: i32* %a8, i32* %bn<br>
+; CHECK: MayAlias: i32* %an, i32* %bn<br>
+; CHECK: MayAlias: i32* %b, i32* %bn<br>
+define void @test_unknown_offset(i32 %n) {<br>
+  %a = alloca [3 x i32], align 4<br>
+  %a4 = getelementptr inbounds [3 x i32], [3 x i32]* %a, i32 0, i32 1<br>
+  %a8 = getelementptr inbounds [3 x i32], [3 x i32]* %a, i32 0, i32 2<br>
+  %an = getelementptr inbounds [3 x i32], [3 x i32]* %a, i32 0, i32 %n<br>
+  %b = bitcast [3 x i32]* %a to i32*<br>
+  %bn = getelementptr inbounds i32, i32* %b, i32 %n<br>
+  ret void<br>
+}<br>
+<br>
+<br>
+%S = type { i32, i32, i32 }<br>
+<br>
+define i32* @return_arg(%S* %arg1, %S* %arg2) {<br>
+  %acast = bitcast %S* %arg1 to i32*<br>
+  %aoffset = getelementptr i32, i32* %acast, i32 1<br>
+  ret i32* %aoffset<br>
+}<br>
+<br>
+define i32* @return_derefence_arg(%S** %arg1) {<br>
+  %deref = load %S*, %S** %arg1<br>
+  %deref2 = getelementptr %S, %S* %deref, i32 0, i32 1<br>
+  ret i32* %deref2<br>
+}<br>
+<br>
+; CHECK-LABEL: Function: test_return_arg_offset<br>
+; CHECK: NoAlias: %S* %a, %S* %b<br>
+; CHECK: MayAlias: %S* %a, i32* %c<br>
+; CHECK: NoAlias: %S* %b, i32* %c<br>
+; CHECK: NoAlias: i32* %acast, i32* %c<br>
+; CHECK: NoAlias: i32* %acast, i32* %d<br>
+define void @test_return_arg_offset() {<br>
+  %a = alloca %S, align 8<br>
+  %b = alloca %S, align 8<br>
+<br>
+  %c = call i32* @return_arg(%S* %a, %S* %b)<br>
+  %d = getelementptr %S, %S* %a, i32 0, i32 1<br>
+  %acast = bitcast %S* %a to i32*<br>
+<br>
+  ret void<br>
+}<br>
+<br>
+; CHECK-LABEL: Function: test_return_derefence_arg<br>
+; CHECK: NoAlias: %S** %p, i32* %c<br>
+; CHECK: NoAlias: %S* %lp, %S** %p<br>
+; CHECK: MayAlias: %S* %lp, i32* %c<br>
+; CHECK: NoAlias: %S** %p, i32* %lp_off<br>
+; CHECK: MayAlias: i32* %c, i32* %lp_off<br>
+; CHECK: MayAlias: %S* %lp, i32* %lp_off<br>
+; CHECK: NoAlias: %S** %p, i32* %acast<br>
+; CHECK: NoAlias: i32* %acast, i32* %c<br>
+; CHECK: MayAlias: %S* %lp, i32* %acast<br>
+; CHECK: NoAlias: i32* %acast, i32* %lp_off<br>
+define void @test_return_derefence_arg() {<br>
+  %a = alloca %S, align 8<br>
+  %p = alloca %S*, align 8<br>
+<br>
+  store %S* %a, %S** %p<br>
+  %c = call i32* @return_derefence_arg(%S** %p)<br>
+<br>
+  %lp = load %S*, %S** %p<br>
+  %lp_off = getelementptr %S, %S* %lp, i32 0, i32 1<br>
+  %acast = bitcast %S* %a to i32*<br>
+<br>
+  ret void<br>
+}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>