[llvm] r275604 - [CFLAA] Add attributes handling for CFLAnders.

George Burgess IV via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 15 13:02:49 PDT 2016


Author: gbiv
Date: Fri Jul 15 15:02:49 2016
New Revision: 275604

URL: http://llvm.org/viewvc/llvm-project?rev=275604&view=rev
Log:
[CFLAA] Add attributes handling for CFLAnders.

This patch adds proper handling of stratified attributes into our
anders-style CFLAA implementation. It also comes bundled with more
CFLAnders tests. :)

Patch by Jia Chen.

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

Added:
    llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/attrs-below.ll
    llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/attrs.ll
Modified:
    llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp

Modified: llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp?rev=275604&r1=275603&r2=275604&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/CFLAndersAliasAnalysis.cpp Fri Jul 15 15:02:49 2016
@@ -141,6 +141,38 @@ public:
   }
 };
 
+// We use AliasAttrMap to keep track of the AliasAttr of each node.
+class AliasAttrMap {
+  typedef DenseMap<InstantiatedValue, AliasAttrs> MapType;
+  MapType AttrMap;
+
+public:
+  typedef MapType::const_iterator const_iterator;
+
+  bool add(InstantiatedValue V, AliasAttrs Attr) {
+    if (Attr.none())
+      return false;
+    auto &OldAttr = AttrMap[V];
+    auto NewAttr = OldAttr | Attr;
+    if (OldAttr == NewAttr)
+      return false;
+    OldAttr = NewAttr;
+    return true;
+  }
+
+  AliasAttrs getAttrs(InstantiatedValue V) const {
+    AliasAttrs Attr;
+    auto Itr = AttrMap.find(V);
+    if (Itr != AttrMap.end())
+      Attr = Itr->second;
+    return Attr;
+  }
+
+  iterator_range<const_iterator> mappings() const {
+    return make_range<const_iterator>(AttrMap.begin(), AttrMap.end());
+  }
+};
+
 struct WorkListItem {
   InstantiatedValue From;
   InstantiatedValue To;
@@ -155,17 +187,33 @@ class CFLAndersAAResult::FunctionInfo {
   /// AliasMap[a] but not vice versa.
   DenseMap<const Value *, std::vector<const Value *>> AliasMap;
 
+  /// Map a value to its corresponding AliasAttrs
+  DenseMap<const Value *, AliasAttrs> AttrMap;
+
   /// Summary of externally visible effects.
   AliasSummary Summary;
 
+  AliasAttrs getAttrs(const Value *) const;
+
 public:
-  FunctionInfo(const ReachabilitySet &);
+  FunctionInfo(const ReachabilitySet &, AliasAttrMap);
 
   bool mayAlias(const Value *LHS, const Value *RHS) const;
   const AliasSummary &getAliasSummary() const { return Summary; }
 };
 
-CFLAndersAAResult::FunctionInfo::FunctionInfo(const ReachabilitySet &ReachSet) {
+CFLAndersAAResult::FunctionInfo::FunctionInfo(const ReachabilitySet &ReachSet,
+                                              AliasAttrMap AMap) {
+  // Populate AttrMap
+  for (const auto &Mapping : AMap.mappings()) {
+    auto IVal = Mapping.first;
+
+    // AttrMap only cares about top-level values
+    if (IVal.DerefLevel == 0)
+      AttrMap[IVal.Val] = Mapping.second;
+  }
+
+  // Populate AliasMap
   for (const auto &OuterMapping : ReachSet.value_mappings()) {
     // AliasMap only cares about top-level values
     if (OuterMapping.first.DerefLevel > 0)
@@ -186,18 +234,39 @@ CFLAndersAAResult::FunctionInfo::Functio
   // TODO: Populate function summary here
 }
 
+AliasAttrs CFLAndersAAResult::FunctionInfo::getAttrs(const Value *V) const {
+  assert(V != nullptr);
+
+  AliasAttrs Attr;
+  auto Itr = AttrMap.find(V);
+  if (Itr != AttrMap.end())
+    Attr = Itr->second;
+  return Attr;
+}
+
 bool CFLAndersAAResult::FunctionInfo::mayAlias(const Value *LHS,
                                                const Value *RHS) const {
   assert(LHS && RHS);
 
   auto Itr = AliasMap.find(LHS);
-  if (Itr == AliasMap.end())
-    return false;
+  if (Itr != AliasMap.end()) {
+    if (std::binary_search(Itr->second.begin(), Itr->second.end(), RHS,
+                           std::less<const Value *>()))
+      return true;
+  }
 
-  // TODO: Check AliasAttrs before drawing any conclusions
+  // Even if LHS and RHS are not reachable, they may still alias due to their
+  // AliasAttrs
+  auto AttrsA = getAttrs(LHS);
+  auto AttrsB = getAttrs(RHS);
 
-  return std::binary_search(Itr->second.begin(), Itr->second.end(), RHS,
-                            std::less<const Value *>());
+  if (AttrsA.none() || AttrsB.none())
+    return false;
+  if (hasUnknownOrCallerAttr(AttrsA) || hasUnknownOrCallerAttr(AttrsB))
+    return true;
+  if (isGlobalOrArgAttr(AttrsA) && isGlobalOrArgAttr(AttrsB))
+    return true;
+  return false;
 }
 
 static void propagate(InstantiatedValue From, InstantiatedValue To,
@@ -247,7 +316,6 @@ static void processWorkListItem(const Wo
   auto NodeInfo = Graph.getNode(ToNode);
   assert(NodeInfo != nullptr);
 
-  // TODO: propagate AliasAttr as well
   // TODO: propagate field offsets
 
   // FIXME: Here is a neat trick we can do: since both ReachSet and MemSet holds
@@ -325,6 +393,52 @@ static void processWorkListItem(const Wo
   }
 }
 
+static AliasAttrMap buildAttrMap(const CFLGraph &Graph,
+                                 const ReachabilitySet &ReachSet) {
+  AliasAttrMap AttrMap;
+  std::vector<InstantiatedValue> WorkList, NextList;
+
+  // Initialize each node with its original AliasAttrs in CFLGraph
+  for (const auto &Mapping : Graph.value_mappings()) {
+    auto Val = Mapping.first;
+    auto &ValueInfo = Mapping.second;
+    for (unsigned I = 0, E = ValueInfo.getNumLevels(); I < E; ++I) {
+      auto Node = InstantiatedValue{Val, I};
+      AttrMap.add(Node, ValueInfo.getNodeInfoAtLevel(I).Attr);
+      WorkList.push_back(Node);
+    }
+  }
+
+  while (!WorkList.empty()) {
+    for (const auto &Dst : WorkList) {
+      auto DstAttr = AttrMap.getAttrs(Dst);
+      if (DstAttr.none())
+        continue;
+
+      // Propagate attr on the same level
+      for (const auto &Mapping : ReachSet.reachableValueAliases(Dst)) {
+        auto Src = Mapping.first;
+        if (AttrMap.add(Src, DstAttr))
+          NextList.push_back(Src);
+      }
+
+      // Propagate attr to the levels below
+      auto DstBelow = getNodeBelow(Graph, Dst);
+      while (DstBelow) {
+        if (AttrMap.add(*DstBelow, DstAttr)) {
+          NextList.push_back(*DstBelow);
+          break;
+        }
+        DstBelow = getNodeBelow(Graph, *DstBelow);
+      }
+    }
+    WorkList.swap(NextList);
+    NextList.clear();
+  }
+
+  return AttrMap;
+}
+
 CFLAndersAAResult::FunctionInfo
 CFLAndersAAResult::buildInfoFrom(const Function &Fn) {
   CFLGraphBuilder<CFLAndersAAResult> GraphBuilder(
@@ -347,7 +461,11 @@ CFLAndersAAResult::buildInfoFrom(const F
     NextList.clear();
   }
 
-  return FunctionInfo(ReachSet);
+  // Now that we have all the reachability info, propagate AliasAttrs according
+  // to it
+  auto IValueAttrMap = buildAttrMap(Graph, ReachSet);
+
+  return FunctionInfo(ReachSet, std::move(IValueAttrMap));
 }
 
 void CFLAndersAAResult::scan(const Function &Fn) {

Added: llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/attrs-below.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/attrs-below.ll?rev=275604&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/attrs-below.ll (added)
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/attrs-below.ll Fri Jul 15 15:02:49 2016
@@ -0,0 +1,61 @@
+; This testcase ensures that AliasAttrs are propagated not only on the same 
+; level but also downward.
+
+; 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-LABEL: Function: test_attr_below
+; CHECK: MayAlias: i64* %q, i64*** %p
+; CHECK: NoAlias: i64* %esc, i64*** %p
+; CHECK: NoAlias: i64* %esc, i64* %q
+
+; CHECK: MayAlias: i64* %unknown, i64*** %p
+; CHECK: MayAlias: i64* %q, i64* %unknown
+; CHECK: MayAlias: i64* %esc, i64* %unknown
+; CHECK: MayAlias: i64* %q, i64** %pdrf
+; CHECK: MayAlias: i64* %esc, i64** %pdrf
+; CHECK: MayAlias: i64* %unknown, i64** %pdrf
+; CHECK: MayAlias: i64* %pdrf2, i64* %q
+; CHECK: MayAlias: i64* %esc, i64* %pdrf2
+; CHECK: MayAlias: i64* %pdrf2, i64* %unknown
+define void @test_attr_below(i64*** %p, i64* %q) {
+  %esc = alloca i64, align 8
+  %escint = ptrtoint i64* %esc to i64
+  %unknown = inttoptr i64 %escint to i64*
+
+  %pdrf = load i64**, i64*** %p
+  %pdrf2 = load i64*, i64** %pdrf
+
+  ret void
+}
+
+; CHECK-LABEL: Function: test_attr_assign_below
+; CHECK: MayAlias: i64** %sel, i64*** %p
+; CHECK: MayAlias: i64* %q, i64** %sel
+; CHECK: MayAlias: i64** %a, i64** %sel
+; CHECK: MayAlias: i64** %pdrf, i64** %sel
+
+; CHECK: MayAlias: i64** %c, i64*** %p
+; CHECK: MayAlias: i64* %q, i64** %c
+; CHECK: MayAlias: i64** %a, i64** %c
+; CHECK: MayAlias: i64** %c, i64** %pdrf
+; CHECK: MayAlias: i64** %c, i64** %sel
+
+; CHECK: MayAlias: i64* %d, i64*** %p
+; CHECK: MayAlias: i64* %d, i64* %q
+; CHECK: MayAlias: i64* %d, i64** %pdrf
+; CHECK: MayAlias: i64* %d, i64** %sel
+define void @test_attr_assign_below(i64*** %p, i64* %q, i1 %cond) {
+  %a = alloca i64*, align 8
+  %pdrf = load i64**, i64*** %p
+  %sel = select i1 %cond, i64** %a, i64** %pdrf
+
+  %b = alloca i64**, align 8
+  store i64** %sel, i64*** %b
+
+  %c = load i64**, i64*** %b
+  %d = load i64*, i64** %c
+
+  ret void
+}
+

Added: llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/attrs.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/attrs.ll?rev=275604&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/attrs.ll (added)
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/Andersen/attrs.ll Fri Jul 15 15:02:49 2016
@@ -0,0 +1,94 @@
+; This testcase ensures that CFL AA handles escaped values no more conservative than it should
+
+; 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-LABEL: Function: test_local
+; CHECK: NoAlias: i32* %a, i32* %b
+; CHECK: MayAlias: i32* %a, i32* %aAlias
+; CHECK: NoAlias: i32* %aAlias, i32* %b
+define void @test_local() {
+	%a = alloca i32, align 4
+	%b = alloca i32, align 4
+	%aint = ptrtoint i32* %a to i64
+	%aAlias = inttoptr i64 %aint to i32*
+	ret void
+}
+
+; CHECK-LABEL: Function: test_global_param
+; CHECK: NoAlias: i32* %a, i32** %x
+; CHECK: MayAlias: i32* %a, i32* %xload
+; CHECK: MayAlias: i32* %a, i32* %gload
+; CHECK: MayAlias: i32* %gload, i32* %xload
+; CHECK: MayAlias: i32** %x, i32** @ext_global
+; CHECK: NoAlias: i32* %a, i32** @ext_global
+ at ext_global = external global i32*
+define void @test_global_param(i32** %x) {
+	%a = alloca i32, align 4
+	%aint = ptrtoint i32* %a to i64
+	%xload = load i32*, i32** %x
+	%gload = load i32*, i32** @ext_global
+	ret void
+}
+
+declare void @external_func(i32**)
+; CHECK-LABEL: Function: test_external_call
+; CHECK: NoAlias: i32* %b, i32* %x
+; CHECK: NoAlias: i32* %b, i32** %a
+; CHECK: MayAlias: i32* %c, i32* %x
+; CHECK: MayAlias: i32* %c, i32** %a
+; CHECK: NoAlias: i32* %b, i32* %c
+define void @test_external_call(i32* %x) {
+	%a = alloca i32*, align 8
+	%b = alloca i32, align 4
+	call void @external_func(i32** %a)
+	%c = load i32*, i32** %a
+	ret void
+}
+
+declare void @external_func_readonly(i32**) readonly
+; CHECK-LABEL: Function: test_external_call_func_readonly
+; CHECK: MayAlias: i32* %c, i32* %x
+; CHECK: NoAlias: i32* %c, i32** %a
+define void @test_external_call_func_readonly(i32* %x) {
+	%a = alloca i32*, align 8
+	%b = alloca i32, align 4
+	store i32* %x, i32** %a, align 4
+	call void @external_func_readonly(i32** %a)
+	%c = load i32*, i32** %a
+	ret void
+}
+
+; CHECK-LABEL: Function: test_external_call_callsite_readonly
+; CHECK: MayAlias: i32* %c, i32* %x
+; CHECK: NoAlias: i32* %c, i32** %a
+define void @test_external_call_callsite_readonly(i32* %x) {
+	%a = alloca i32*, align 8
+	%b = alloca i32, align 4
+	store i32* %x, i32** %a, align 4
+	call void @external_func(i32** %a) readonly
+	%c = load i32*, i32** %a
+	ret void
+}
+
+declare i32* @external_func_normal_return(i32*)
+; CHECK-LABEL: Function: test_external_call_normal_return
+; CHECK: MayAlias: i32* %c, i32* %x
+; CHECK: MayAlias: i32* %a, i32* %c
+define void @test_external_call_normal_return(i32* %x) {
+	%a = alloca i32, align 8
+	%b = alloca i32, align 4
+	%c = call i32* @external_func_normal_return(i32* %a)
+	ret void
+}
+
+declare noalias i32* @external_func_noalias_return(i32*)
+; CHECK-LABEL: Function: test_external_call_noalias_return
+; CHECK: NoAlias: i32* %c, i32* %x
+; CHECK: NoAlias: i32* %a, i32* %c
+define void @test_external_call_noalias_return(i32* %x) {
+	%a = alloca i32, align 8
+	%b = alloca i32, align 4
+	%c = call i32* @external_func_noalias_return(i32* %a)
+	ret void
+}




More information about the llvm-commits mailing list