[llvm] r332657 - [AA] cfl-anders-aa with field sensitivity

David Bolvansky via llvm-commits llvm-commits at lists.llvm.org
Thu May 17 13:23:33 PDT 2018


Author: xbolva00
Date: Thu May 17 13:23:33 2018
New Revision: 332657

URL: http://llvm.org/viewvc/llvm-project?rev=332657&view=rev
Log:
[AA] cfl-anders-aa with field sensitivity

Summary:
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.

The performance results seem promising.

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)

Reviewers: chandlerc, george.burgess.iv, rja

Reviewed By: rja

Subscribers: rja, llvm-commits

Differential Revision: https://reviews.llvm.org/D46282

Added:
    llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/field.ll
Modified:
    llvm/trunk/lib/Analysis/AliasAnalysisSummary.h
    llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp
    llvm/trunk/lib/Analysis/CFLGraph.h

Modified: llvm/trunk/lib/Analysis/AliasAnalysisSummary.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/AliasAnalysisSummary.h?rev=332657&r1=332656&r2=332657&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/AliasAnalysisSummary.h (original)
+++ llvm/trunk/lib/Analysis/AliasAnalysisSummary.h Thu May 17 13:23:33 2018
@@ -134,18 +134,31 @@ inline bool operator>=(InterfaceValue LH
   return !(LHS < RHS);
 }
 
+using FieldOffset = int64_t;
 // We use UnknownOffset to represent pointer offsets that cannot be determined
 // at compile time. Note that MemoryLocation::UnknownSize cannot be used here
 // because we require a signed value.
-static const int64_t UnknownOffset = INT64_MAX;
+static const FieldOffset UnknownOffset =
+    std::numeric_limits<FieldOffset>::max();
 
-inline int64_t addOffset(int64_t LHS, int64_t RHS) {
+inline FieldOffset addFieldOffset(FieldOffset LHS, FieldOffset RHS) {
   if (LHS == UnknownOffset || RHS == UnknownOffset)
     return UnknownOffset;
-  // FIXME: Do we need to guard against integer overflow here?
+
   return LHS + RHS;
 }
 
+inline FieldOffset subFieldOffset(FieldOffset LHS, FieldOffset RHS) {
+  if (LHS == UnknownOffset || RHS == UnknownOffset)
+    return UnknownOffset;
+
+  return LHS - RHS;
+}
+
+inline FieldOffset negFieldOffset(FieldOffset Offset) {
+  return subFieldOffset(0, Offset);
+}
+
 /// We use ExternalRelation to describe an externally visible aliasing relations
 /// between parameters/return value of a function.
 struct ExternalRelation {

Modified: llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp?rev=332657&r1=332656&r2=332657&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp Thu May 17 13:23:33 2018
@@ -153,11 +153,59 @@ struct OffsetInstantiatedValue {
 bool operator==(OffsetInstantiatedValue LHS, OffsetInstantiatedValue RHS) {
   return LHS.IVal == RHS.IVal && LHS.Offset == RHS.Offset;
 }
+}
+
+namespace llvm {
+
+// Specialize DenseMapInfo for OffsetValue.
+template <> struct DenseMapInfo<OffsetValue> {
+  static OffsetValue getEmptyKey() {
+    return OffsetValue{DenseMapInfo<const Value *>::getEmptyKey(),
+                       DenseMapInfo<FieldOffset>::getEmptyKey()};
+  }
+  static OffsetValue getTombstoneKey() {
+    return OffsetValue{DenseMapInfo<const Value *>::getTombstoneKey(),
+                       DenseMapInfo<FieldOffset>::getEmptyKey()};
+  }
+  static unsigned getHashValue(const OffsetValue &OVal) {
+    return DenseMapInfo<std::pair<const Value *, FieldOffset>>::getHashValue(
+        std::make_pair(OVal.Val, OVal.Offset));
+  }
+  static bool isEqual(const OffsetValue &LHS, const OffsetValue &RHS) {
+    return LHS == RHS;
+  }
+};
+
+// Specialize DenseMapInfo for OffsetInstantiatedValue.
+template <> struct DenseMapInfo<OffsetInstantiatedValue> {
+  static OffsetInstantiatedValue getEmptyKey() {
+    return OffsetInstantiatedValue{
+        DenseMapInfo<InstantiatedValue>::getEmptyKey(),
+        DenseMapInfo<FieldOffset>::getEmptyKey()};
+  }
+  static OffsetInstantiatedValue getTombstoneKey() {
+    return OffsetInstantiatedValue{
+        DenseMapInfo<InstantiatedValue>::getTombstoneKey(),
+        DenseMapInfo<FieldOffset>::getEmptyKey()};
+  }
+  static unsigned getHashValue(const OffsetInstantiatedValue &OVal) {
+    return DenseMapInfo<std::pair<InstantiatedValue, FieldOffset>>::
+        getHashValue(std::make_pair(OVal.IVal, OVal.Offset));
+  }
+  static bool isEqual(const OffsetInstantiatedValue &LHS,
+                      const OffsetInstantiatedValue &RHS) {
+    return LHS == RHS;
+  }
+};
+
+} // namespace llvm
+
+namespace {
 
 // We use ReachabilitySet to keep track of value aliases (The nonterminal "V" in
 // the paper) during the analysis.
 class ReachabilitySet {
-  using ValueStateMap = DenseMap<InstantiatedValue, StateSet>;
+  using ValueStateMap = DenseMap<OffsetInstantiatedValue, StateSet>;
   using ValueReachMap = DenseMap<InstantiatedValue, ValueStateMap>;
 
   ValueReachMap ReachMap;
@@ -166,10 +214,11 @@ public:
   using const_valuestate_iterator = ValueStateMap::const_iterator;
   using const_value_iterator = ValueReachMap::const_iterator;
 
-  // Insert edge 'From->To' at state 'State'
-  bool insert(InstantiatedValue From, InstantiatedValue To, MatchState State) {
+  // Insert edge 'From->To' at state 'State' with offset 'Offset'
+  bool insert(InstantiatedValue From, InstantiatedValue To, FieldOffset Offset,
+              MatchState State) {
     assert(From != To);
-    auto &States = ReachMap[To][From];
+    auto &States = ReachMap[To][OffsetInstantiatedValue{From, Offset}];
     auto Idx = static_cast<size_t>(State);
     if (!States.test(Idx)) {
       States.set(Idx);
@@ -254,6 +303,7 @@ public:
 struct WorkListItem {
   InstantiatedValue From;
   InstantiatedValue To;
+  FieldOffset Offset;
   MatchState State;
 };
 
@@ -261,63 +311,13 @@ struct ValueSummary {
   struct Record {
     InterfaceValue IValue;
     unsigned DerefLevel;
+    FieldOffset Offset;
   };
   SmallVector<Record, 4> FromRecords, ToRecords;
 };
 
 } // end anonymous namespace
 
-namespace llvm {
-
-// Specialize DenseMapInfo for OffsetValue.
-template <> struct DenseMapInfo<OffsetValue> {
-  static OffsetValue getEmptyKey() {
-    return OffsetValue{DenseMapInfo<const Value *>::getEmptyKey(),
-                       DenseMapInfo<int64_t>::getEmptyKey()};
-  }
-
-  static OffsetValue getTombstoneKey() {
-    return OffsetValue{DenseMapInfo<const Value *>::getTombstoneKey(),
-                       DenseMapInfo<int64_t>::getEmptyKey()};
-  }
-
-  static unsigned getHashValue(const OffsetValue &OVal) {
-    return DenseMapInfo<std::pair<const Value *, int64_t>>::getHashValue(
-        std::make_pair(OVal.Val, OVal.Offset));
-  }
-
-  static bool isEqual(const OffsetValue &LHS, const OffsetValue &RHS) {
-    return LHS == RHS;
-  }
-};
-
-// Specialize DenseMapInfo for OffsetInstantiatedValue.
-template <> struct DenseMapInfo<OffsetInstantiatedValue> {
-  static OffsetInstantiatedValue getEmptyKey() {
-    return OffsetInstantiatedValue{
-        DenseMapInfo<InstantiatedValue>::getEmptyKey(),
-        DenseMapInfo<int64_t>::getEmptyKey()};
-  }
-
-  static OffsetInstantiatedValue getTombstoneKey() {
-    return OffsetInstantiatedValue{
-        DenseMapInfo<InstantiatedValue>::getTombstoneKey(),
-        DenseMapInfo<int64_t>::getEmptyKey()};
-  }
-
-  static unsigned getHashValue(const OffsetInstantiatedValue &OVal) {
-    return DenseMapInfo<std::pair<InstantiatedValue, int64_t>>::getHashValue(
-        std::make_pair(OVal.IVal, OVal.Offset));
-  }
-
-  static bool isEqual(const OffsetInstantiatedValue &LHS,
-                      const OffsetInstantiatedValue &RHS) {
-    return LHS == RHS;
-  }
-};
-
-} // end namespace llvm
-
 class CFLAndersAAResult::FunctionInfo {
   /// Map a value to other values that may alias it
   /// Since the alias relation is symmetric, to save some space we assume values
@@ -389,9 +389,11 @@ populateAliasMap(DenseMap<const Value *,
     auto Val = OuterMapping.first.Val;
     auto &AliasList = AliasMap[Val];
     for (const auto &InnerMapping : OuterMapping.second) {
+      auto OVal = InnerMapping.first;
       // Again, AliasMap only cares about top-level values
-      if (InnerMapping.first.DerefLevel == 0)
-        AliasList.push_back(OffsetValue{InnerMapping.first.Val, UnknownOffset});
+      if (OVal.IVal.DerefLevel == 0)
+        AliasList.push_back(
+            OffsetValue{OVal.IVal.Val, negFieldOffset(OVal.Offset)});
     }
 
     // Sort AliasList for faster lookup
@@ -430,24 +432,27 @@ static void populateExternalRelations(
   for (const auto &OuterMapping : ReachSet.value_mappings()) {
     if (auto Dst = getInterfaceValue(OuterMapping.first, RetVals)) {
       for (const auto &InnerMapping : OuterMapping.second) {
+        auto OVal = InnerMapping.first;
+        auto SrcIVal = OVal.IVal;
+        auto Offset = OVal.Offset;
         // If Src is a param/return value, we get a same-level assignment.
-        if (auto Src = getInterfaceValue(InnerMapping.first, RetVals)) {
+        if (auto Src = getInterfaceValue(SrcIVal, RetVals)) {
           // This may happen if both Dst and Src are return values
           if (*Dst == *Src)
             continue;
 
           if (hasReadOnlyState(InnerMapping.second))
-            ExtRelations.push_back(ExternalRelation{*Dst, *Src, UnknownOffset});
+            ExtRelations.push_back(ExternalRelation{*Dst, *Src, Offset});
           // No need to check for WriteOnly state, since ReachSet is symmetric
         } else {
           // If Src is not a param/return, add it to ValueMap
-          auto SrcIVal = InnerMapping.first;
+
           if (hasReadOnlyState(InnerMapping.second))
             ValueMap[SrcIVal.Val].FromRecords.push_back(
-                ValueSummary::Record{*Dst, SrcIVal.DerefLevel});
+                ValueSummary::Record{*Dst, SrcIVal.DerefLevel, Offset});
           if (hasWriteOnlyState(InnerMapping.second))
             ValueMap[SrcIVal.Val].ToRecords.push_back(
-                ValueSummary::Record{*Dst, SrcIVal.DerefLevel});
+                ValueSummary::Record{*Dst, SrcIVal.DerefLevel, Offset});
         }
       }
     }
@@ -466,14 +471,20 @@ static void populateExternalRelations(
         auto SrcLevel = FromRecord.IValue.DerefLevel;
         auto DstIndex = ToRecord.IValue.Index;
         auto DstLevel = ToRecord.IValue.DerefLevel;
+
+        // Offsets to be pushed to External Relations
+        auto SrcOffset = FromRecord.Offset;
+        auto DstOffset = ToRecord.Offset;
+
         if (ToLevel > FromLevel)
           SrcLevel += ToLevel - FromLevel;
         else
           DstLevel += FromLevel - ToLevel;
 
-        ExtRelations.push_back(ExternalRelation{
-            InterfaceValue{SrcIndex, SrcLevel},
-            InterfaceValue{DstIndex, DstLevel}, UnknownOffset});
+        ExtRelations.push_back(
+            ExternalRelation{InterfaceValue{SrcIndex, SrcLevel},
+                             InterfaceValue{DstIndex, DstLevel},
+                             subFieldOffset(SrcOffset, DstOffset)});
       }
     }
   }
@@ -591,12 +602,14 @@ bool CFLAndersAAResult::FunctionInfo::ma
 }
 
 static void propagate(InstantiatedValue From, InstantiatedValue To,
-                      MatchState State, ReachabilitySet &ReachSet,
+                      FieldOffset Offset, MatchState State,
+                      ReachabilitySet &ReachSet,
                       std::vector<WorkListItem> &WorkList) {
   if (From == To)
     return;
-  if (ReachSet.insert(From, To, State))
-    WorkList.push_back(WorkListItem{From, To, State});
+
+  if (ReachSet.insert(From, To, Offset, State))
+    WorkList.push_back(WorkListItem{From, To, Offset, State});
 }
 
 static void initializeWorkList(std::vector<WorkListItem> &WorkList,
@@ -610,13 +623,15 @@ static void initializeWorkList(std::vect
     // Insert all immediate assignment neighbors to the worklist
     for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) {
       auto Src = InstantiatedValue{Val, I};
-      // If there's an assignment edge from X to Y, it means Y is reachable from
-      // X at S2 and X is reachable from Y at S1
+      // If we have an assignment edge from X + Offset to Y, it means that
+      // (Y - Offset) is reachable from X at the state FlowToWriteOnly
+      // At the same time, (X + Offset) is reachable from Y at the state
+      // FlowFromReadOnly
       for (auto &Edge : ValueInfo.getNodeInfoAtLevel(I).Edges) {
-        propagate(Edge.Other, Src, MatchState::FlowFromReadOnly, ReachSet,
-                  WorkList);
-        propagate(Src, Edge.Other, MatchState::FlowToWriteOnly, ReachSet,
-                  WorkList);
+        propagate(Edge.Other, Src, Edge.Offset, MatchState::FlowFromReadOnly,
+                  ReachSet, WorkList);
+        propagate(Src, Edge.Other, negFieldOffset(Edge.Offset),
+                  MatchState::FlowToWriteOnly, ReachSet, WorkList);
       }
     }
   }
@@ -635,37 +650,41 @@ static void processWorkListItem(const Wo
                                 std::vector<WorkListItem> &WorkList) {
   auto FromNode = Item.From;
   auto ToNode = Item.To;
+  auto Offset = Item.Offset;
 
   auto NodeInfo = Graph.getNode(ToNode);
   assert(NodeInfo != nullptr);
 
-  // TODO: propagate field offsets
-
   // FIXME: Here is a neat trick we can do: since both ReachSet and MemSet holds
   // relations that are symmetric, we could actually cut the storage by half by
   // sorting FromNode and ToNode before insertion happens.
 
   // The newly added value alias pair may potentially generate more memory
   // alias pairs. Check for them here.
-  auto FromNodeBelow = getNodeBelow(Graph, FromNode);
-  auto ToNodeBelow = getNodeBelow(Graph, ToNode);
-  if (FromNodeBelow && ToNodeBelow &&
-      MemSet.insert(*FromNodeBelow, *ToNodeBelow)) {
-    propagate(*FromNodeBelow, *ToNodeBelow,
-              MatchState::FlowFromMemAliasNoReadWrite, ReachSet, WorkList);
-    for (const auto &Mapping : ReachSet.reachableValueAliases(*FromNodeBelow)) {
-      auto Src = Mapping.first;
-      auto MemAliasPropagate = [&](MatchState FromState, MatchState ToState) {
-        if (Mapping.second.test(static_cast<size_t>(FromState)))
-          propagate(Src, *ToNodeBelow, ToState, ReachSet, WorkList);
-      };
-
-      MemAliasPropagate(MatchState::FlowFromReadOnly,
-                        MatchState::FlowFromMemAliasReadOnly);
-      MemAliasPropagate(MatchState::FlowToWriteOnly,
-                        MatchState::FlowToMemAliasWriteOnly);
-      MemAliasPropagate(MatchState::FlowToReadWrite,
-                        MatchState::FlowToMemAliasReadWrite);
+  // MemAlias reachability can only be triggered when Offset is 0 or Unknown
+  if (Offset == 0 || Offset == UnknownOffset) {
+    auto FromNodeBelow = getNodeBelow(Graph, FromNode);
+    auto ToNodeBelow = getNodeBelow(Graph, ToNode);
+    if (FromNodeBelow && ToNodeBelow &&
+        MemSet.insert(*FromNodeBelow, *ToNodeBelow)) {
+      propagate(*FromNodeBelow, *ToNodeBelow, Offset,
+                MatchState::FlowFromMemAliasNoReadWrite, ReachSet, WorkList);
+      for (const auto &Mapping :
+           ReachSet.reachableValueAliases(*FromNodeBelow)) {
+        auto SrcOVal = Mapping.first;
+        auto MemAliasPropagate = [&](MatchState FromState, MatchState ToState) {
+          if (Mapping.second.test(static_cast<size_t>(FromState)))
+            propagate(SrcOVal.IVal, *ToNodeBelow, SrcOVal.Offset, ToState,
+                      ReachSet, WorkList);
+        };
+
+        MemAliasPropagate(MatchState::FlowFromReadOnly,
+                          MatchState::FlowFromMemAliasReadOnly);
+        MemAliasPropagate(MatchState::FlowToWriteOnly,
+                          MatchState::FlowToMemAliasWriteOnly);
+        MemAliasPropagate(MatchState::FlowToReadWrite,
+                          MatchState::FlowToMemAliasReadWrite);
+      }
     }
   }
 
@@ -678,17 +697,23 @@ static void processWorkListItem(const Wo
   // - If Y is an alias of X, then reverse assignment edges (if there is any)
   // should precede any assignment edges on the path from X to Y.
   auto NextAssignState = [&](MatchState State) {
-    for (const auto &AssignEdge : NodeInfo->Edges)
-      propagate(FromNode, AssignEdge.Other, State, ReachSet, WorkList);
+    for (const auto &AssignEdge : NodeInfo->Edges) {
+      propagate(FromNode, AssignEdge.Other,
+                subFieldOffset(Offset, AssignEdge.Offset), State, ReachSet,
+                WorkList);
+    }
   };
   auto NextRevAssignState = [&](MatchState State) {
-    for (const auto &RevAssignEdge : NodeInfo->ReverseEdges)
-      propagate(FromNode, RevAssignEdge.Other, State, ReachSet, WorkList);
+    for (const auto &RevAssignEdge : NodeInfo->ReverseEdges) {
+      propagate(FromNode, RevAssignEdge.Other,
+                addFieldOffset(Offset, RevAssignEdge.Offset), State, ReachSet,
+                WorkList);
+    }
   };
   auto NextMemState = [&](MatchState State) {
     if (auto AliasSet = MemSet.getMemoryAliases(ToNode)) {
       for (const auto &MemAlias : *AliasSet)
-        propagate(FromNode, MemAlias, State, ReachSet, WorkList);
+        propagate(FromNode, MemAlias, Offset, State, ReachSet, WorkList);
     }
   };
 
@@ -753,7 +778,7 @@ static AliasAttrMap buildAttrMap(const C
 
       // Propagate attr on the same level
       for (const auto &Mapping : ReachSet.reachableValueAliases(Dst)) {
-        auto Src = Mapping.first;
+        auto Src = Mapping.first.IVal;
         if (AttrMap.add(Src, DstAttr))
           NextList.push_back(Src);
       }
@@ -788,11 +813,19 @@ CFLAndersAAResult::buildInfoFrom(const F
 
   std::vector<WorkListItem> WorkList, NextList;
   initializeWorkList(WorkList, ReachSet, Graph);
-  // TODO: make sure we don't stop before the fix point is reached
+
+  bool LoopInGraph = false;
   while (!WorkList.empty()) {
     for (const auto &Item : WorkList)
       processWorkListItem(Item, Graph, ReachSet, MemSet, NextList);
 
+    if (NextList.size() == WorkList.size()) {
+      // stop if loop in CFL graph
+      if (LoopInGraph)
+        break;
+      LoopInGraph = true;
+    }
+
     NextList.swap(WorkList);
     NextList.clear();
   }

Modified: llvm/trunk/lib/Analysis/CFLGraph.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CFLGraph.h?rev=332657&r1=332656&r2=332657&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/CFLGraph.h (original)
+++ llvm/trunk/lib/Analysis/CFLGraph.h Thu May 17 13:23:33 2018
@@ -62,7 +62,7 @@ public:
 
   struct Edge {
     Node Other;
-    int64_t Offset;
+    FieldOffset Offset;
   };
 
   using EdgeList = std::vector<Edge>;
@@ -125,7 +125,7 @@ public:
     Info->Attr |= Attr;
   }
 
-  void addEdge(Node From, Node To, int64_t Offset = 0) {
+  void addEdge(Node From, Node To, FieldOffset Offset = 0) {
     auto *FromInfo = getNode(From);
     assert(FromInfo != nullptr);
     auto *ToInfo = getNode(To);
@@ -219,7 +219,7 @@ template <typename CFLAA> class CFLGraph
         Graph.addNode(InstantiatedValue{Val, 0}, Attr);
     }
 
-    void addAssignEdge(Value *From, Value *To, int64_t Offset = 0) {
+    void addAssignEdge(Value *From, Value *To, FieldOffset Offset = 0) {
       assert(From != nullptr && To != nullptr);
       if (!From->getType()->isPointerTy() || !To->getType()->isPointerTy())
         return;
@@ -312,7 +312,7 @@ template <typename CFLAA> class CFLGraph
     }
 
     void visitGEP(GEPOperator &GEPOp) {
-      uint64_t Offset = UnknownOffset;
+      FieldOffset Offset = UnknownOffset;
       APInt APOffset(DL.getPointerSizeInBits(GEPOp.getPointerAddressSpace()),
                      0);
       if (GEPOp.accumulateConstantOffset(DL, APOffset))
@@ -397,7 +397,7 @@ template <typename CFLAA> class CFLGraph
           if (IRelation.hasValue()) {
             Graph.addNode(IRelation->From);
             Graph.addNode(IRelation->To);
-            Graph.addEdge(IRelation->From, IRelation->To);
+            Graph.addEdge(IRelation->From, IRelation->To, IRelation->Offset);
           }
         }
 

Added: llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/field.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/field.ll?rev=332657&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/field.ll (added)
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/field.ll Thu May 17 13:23:33 2018
@@ -0,0 +1,102 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -disable-basicaa -cfl-anders-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+; RUN: opt < %s -aa-pipeline=cfl-anders-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+; CHECK: Function: test_simple_offsets
+; CHECK: NoAlias: i64* %b, i64** %acast
+; CHECK: NoAlias: i64** %acast, i64** %aoff
+; CHECK: NoAlias: i64* %b, i64** %acastoff
+; CHECK: NoAlias: i64** %acast, i64** %acastoff
+; CHECK: NoAlias: [2 x i64*]* %a, i64* %acastload
+; CHECK: MayAlias: i64* %acastload, i64* %b
+; CHECK: NoAlias: i64* %acastload, i64** %aoff
+; CHECK: NoAlias: i64* %acastload, i64** %acast
+; CHECK: NoAlias: i64* %acastload, i64** %acastoff
+define void @test_simple_offsets() {
+  %a = alloca [2 x i64*], align 8
+  %b = alloca i64, align 4
+  %aoff = getelementptr inbounds [2 x i64*], [2 x i64*]* %a, i64 0, i64 1
+  store i64* %b, i64** %aoff
+
+  %acast = bitcast [2 x i64*]* %a to i64**
+  %acastoff = getelementptr inbounds i64*, i64** %acast, i64 1
+  %acastload = load i64*, i64** %acastoff
+  ret void
+}
+
+; CHECK: Function: test_unknown_offset
+; CHECK: MayAlias: [3 x i32]* %a, i32* %an
+; CHECK: MayAlias: i32* %a4, i32* %an
+; CHECK: MayAlias: i32* %a8, i32* %an
+; CHECK: MayAlias: i32* %an, i32* %b
+; CHECK: MayAlias: [3 x i32]* %a, i32* %bn
+; CHECK: MayAlias: i32* %a4, i32* %bn
+; CHECK: MayAlias: i32* %a8, i32* %bn
+; CHECK: MayAlias: i32* %an, i32* %bn
+; CHECK: MayAlias: i32* %b, i32* %bn
+define void @test_unknown_offset(i32 %n) {
+  %a = alloca [3 x i32], align 4
+  %a4 = getelementptr inbounds [3 x i32], [3 x i32]* %a, i32 0, i32 1
+  %a8 = getelementptr inbounds [3 x i32], [3 x i32]* %a, i32 0, i32 2
+  %an = getelementptr inbounds [3 x i32], [3 x i32]* %a, i32 0, i32 %n
+  %b = bitcast [3 x i32]* %a to i32*
+  %bn = getelementptr inbounds i32, i32* %b, i32 %n
+  ret void
+}
+
+
+%S = type { i32, i32, i32 }
+
+define i32* @return_arg(%S* %arg1, %S* %arg2) {
+  %acast = bitcast %S* %arg1 to i32*
+  %aoffset = getelementptr i32, i32* %acast, i32 1
+  ret i32* %aoffset
+}
+
+define i32* @return_derefence_arg(%S** %arg1) {
+  %deref = load %S*, %S** %arg1
+  %deref2 = getelementptr %S, %S* %deref, i32 0, i32 1
+  ret i32* %deref2
+}
+
+; CHECK-LABEL: Function: test_return_arg_offset
+; CHECK: NoAlias: %S* %a, %S* %b
+; CHECK: MayAlias: %S* %a, i32* %c
+; CHECK: NoAlias: %S* %b, i32* %c
+; CHECK: NoAlias: i32* %acast, i32* %c
+; CHECK: NoAlias: i32* %acast, i32* %d
+define void @test_return_arg_offset() {
+  %a = alloca %S, align 8
+  %b = alloca %S, align 8
+
+  %c = call i32* @return_arg(%S* %a, %S* %b)
+  %d = getelementptr %S, %S* %a, i32 0, i32 1
+  %acast = bitcast %S* %a to i32*
+
+  ret void
+}
+
+; CHECK-LABEL: Function: test_return_derefence_arg
+; CHECK: NoAlias: %S** %p, i32* %c
+; CHECK: NoAlias: %S* %lp, %S** %p
+; CHECK: MayAlias: %S* %lp, i32* %c
+; CHECK: NoAlias: %S** %p, i32* %lp_off
+; CHECK: MayAlias: i32* %c, i32* %lp_off
+; CHECK: MayAlias: %S* %lp, i32* %lp_off
+; CHECK: NoAlias: %S** %p, i32* %acast
+; CHECK: NoAlias: i32* %acast, i32* %c
+; CHECK: MayAlias: %S* %lp, i32* %acast
+; CHECK: NoAlias: i32* %acast, i32* %lp_off
+define void @test_return_derefence_arg() {
+  %a = alloca %S, align 8
+  %p = alloca %S*, align 8
+
+  store %S* %a, %S** %p
+  %c = call i32* @return_derefence_arg(%S** %p)
+
+  %lp = load %S*, %S** %p
+  %lp_off = getelementptr %S, %S* %lp, i32 0, i32 1
+  %acast = bitcast %S* %a to i32*
+
+  ret void
+}




More information about the llvm-commits mailing list