[llvm] r273219 - [CFLAA] Add interprocedural function summaries.

George Burgess IV via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 20 16:10:56 PDT 2016


Author: gbiv
Date: Mon Jun 20 18:10:56 2016
New Revision: 273219

URL: http://llvm.org/viewvc/llvm-project?rev=273219&view=rev
Log:
[CFLAA] Add interprocedural function summaries.

This patch adds function summaries, so that we don't need to recompute
various properties about function parameters/return values at each
callsite of a function. It also adds many interprocedural tests for
CFLAA.

Patch by Jia Chen.

Differential Revision: http://reviews.llvm.org/D21475#inline-182390

Added:
    llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-arg.ll
    llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-deref-arg-multilevel.ll
    llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-deref-arg.ll
    llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-ref-arg-multilevel.ll
    llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-ref-arg.ll
    llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-unknown.ll
    llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg-multilevel.ll
    llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg-unknown.ll
    llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg.ll
Modified:
    llvm/trunk/include/llvm/Analysis/CFLAliasAnalysis.h
    llvm/trunk/lib/Analysis/CFLAliasAnalysis.cpp
    llvm/trunk/test/Analysis/CFLAliasAnalysis/basic-interproc.ll

Modified: llvm/trunk/include/llvm/Analysis/CFLAliasAnalysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/CFLAliasAnalysis.h?rev=273219&r1=273218&r2=273219&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/CFLAliasAnalysis.h (original)
+++ llvm/trunk/include/llvm/Analysis/CFLAliasAnalysis.h Mon Jun 20 18:10:56 2016
@@ -30,8 +30,7 @@ class TargetLibraryInfo;
 
 class CFLAAResult : public AAResultBase<CFLAAResult> {
   friend AAResultBase<CFLAAResult>;
-
-  struct FunctionInfo;
+  class FunctionInfo;
 
 public:
   explicit CFLAAResult(const TargetLibraryInfo &);

Modified: llvm/trunk/lib/Analysis/CFLAliasAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CFLAliasAnalysis.cpp?rev=273219&r1=273218&r2=273219&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/CFLAliasAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/CFLAliasAnalysis.cpp Mon Jun 20 18:10:56 2016
@@ -64,14 +64,30 @@ CFLAAResult::CFLAAResult(CFLAAResult &&A
     : AAResultBase(std::move(Arg)), TLI(Arg.TLI) {}
 CFLAAResult::~CFLAAResult() {}
 
+/// We use ExternalRelation to describe an externally visible interaction
+/// between parameters/return value of a function.
+/// Both From and To are integer indices that represent a single parameter or
+/// return value. When the index is 0, they represent the return value. Non-zero
+/// index i represents the i-th parameter.
+struct ExternalRelation {
+  unsigned From, To;
+};
+
 /// Information we have about a function and would like to keep around.
-struct CFLAAResult::FunctionInfo {
+class CFLAAResult::FunctionInfo {
   StratifiedSets<Value *> Sets;
-  // Lots of functions have < 4 returns. Adjust as necessary.
-  SmallVector<Value *, 4> ReturnedValues;
 
-  FunctionInfo(StratifiedSets<Value *> &&S, SmallVector<Value *, 4> &&RV)
-      : Sets(std::move(S)), ReturnedValues(std::move(RV)) {}
+  // RetParamRelations is a collection of ExternalRelations.
+  SmallVector<ExternalRelation, 8> RetParamRelations;
+
+public:
+  FunctionInfo(Function &Fn, const SmallVectorImpl<Value *> &RetVals,
+               StratifiedSets<Value *> S);
+
+  const StratifiedSets<Value *> &getStratifiedSets() const { return Sets; }
+  const SmallVectorImpl<ExternalRelation> &getRetParamRelations() const {
+    return RetParamRelations;
+  }
 };
 
 /// Try to go from a Value* to a Function*. Never returns nullptr.
@@ -101,6 +117,9 @@ LLVM_CONSTEXPR StratifiedAttr AttrEscape
 LLVM_CONSTEXPR StratifiedAttr AttrUnknown = 1 << AttrUnknownIndex;
 LLVM_CONSTEXPR StratifiedAttr AttrGlobal = 1 << AttrGlobalIndex;
 
+/// The maximum number of arguments we can put into a summary.
+LLVM_CONSTEXPR unsigned MaxSupportedArgsInSummary = 50;
+
 /// StratifiedSets call for knowledge of "direction", so this is how we
 /// represent that locally.
 enum class Level { Same, Above, Below };
@@ -361,147 +380,45 @@ public:
     return Fn->isDeclaration() || !Fn->hasLocalLinkage();
   }
 
-  /// Gets whether the sets at Index1 above, below, or equal to the sets at
-  /// Index2. Returns None if they are not in the same set chain.
-  static Optional<Level> getIndexRelation(const StratifiedSets<Value *> &Sets,
-                                          StratifiedIndex Index1,
-                                          StratifiedIndex Index2) {
-    if (Index1 == Index2)
-      return Level::Same;
-
-    const auto *Current = &Sets.getLink(Index1);
-    while (Current->hasBelow()) {
-      if (Current->Below == Index2)
-        return Level::Below;
-      Current = &Sets.getLink(Current->Below);
-    }
-
-    Current = &Sets.getLink(Index1);
-    while (Current->hasAbove()) {
-      if (Current->Above == Index2)
-        return Level::Above;
-      Current = &Sets.getLink(Current->Above);
-    }
-
-    return None;
-  }
-
-  // Encodes the notion of a "use"
-  struct Edge {
-    // Which value the edge is coming from
-    Value *From;
-
-    // Which value the edge is pointing to
-    Value *To;
-
-    // Edge weight
-    EdgeType Weight;
-
-    // Whether we aliased any external values along the way that may be
-    // invisible to the analysis
-    StratifiedAttrs FromAttrs, ToAttrs;
-  };
-
-  bool
-  tryInterproceduralAnalysis(const SmallVectorImpl<Function *> &Fns,
-                             Value *FuncValue,
-                             const iterator_range<User::op_iterator> &Args) {
-    const unsigned ExpectedMaxArgs = 8;
-    const unsigned MaxSupportedArgs = 50;
+  bool tryInterproceduralAnalysis(CallSite CS,
+                                  const SmallVectorImpl<Function *> &Fns) {
     assert(Fns.size() > 0);
 
-    // This algorithm is n^2, so an arbitrary upper-bound of 50 args was
-    // selected, so it doesn't take too long in insane cases.
-    if (std::distance(Args.begin(), Args.end()) > (int)MaxSupportedArgs)
+    if (CS.arg_size() > MaxSupportedArgsInSummary)
       return false;
 
     // Exit early if we'll fail anyway
     for (auto *Fn : Fns) {
       if (isFunctionExternal(Fn) || Fn->isVarArg())
         return false;
+      // Fail if the caller does not provide enough arguments
+      assert(Fn->arg_size() <= CS.arg_size());
       auto &MaybeInfo = AA.ensureCached(Fn);
       if (!MaybeInfo.hasValue())
         return false;
     }
 
-    SmallVector<Edge, 8> Output;
-    SmallVector<Value *, ExpectedMaxArgs> Arguments(Args.begin(), Args.end());
-    SmallVector<StratifiedInfo, ExpectedMaxArgs> Parameters;
     for (auto *Fn : Fns) {
-      auto &Info = *AA.ensureCached(Fn);
-      auto &Sets = Info.Sets;
-      auto &RetVals = Info.ReturnedValues;
-
-      Parameters.clear();
-      for (auto &Param : Fn->args()) {
-        auto MaybeInfo = Sets.find(&Param);
-        // Did a new parameter somehow get added to the function/slip by?
-        if (!MaybeInfo.hasValue())
-          return false;
-        Parameters.push_back(*MaybeInfo);
-      }
-
-      // Adding an edge from argument -> return value for each parameter that
-      // may alias the return value
-      for (unsigned I = 0, E = Parameters.size(); I != E; ++I) {
-        auto &ParamInfo = Parameters[I];
-        auto &ArgVal = Arguments[I];
-        bool AddEdge = false;
-        StratifiedAttrs RetAttrs, ParamAttrs;
-        for (unsigned X = 0, XE = RetVals.size(); X != XE; ++X) {
-          auto MaybeInfo = Sets.find(RetVals[X]);
-          if (!MaybeInfo.hasValue())
-            return false;
-
-          auto &RetInfo = *MaybeInfo;
-          RetAttrs |= Sets.getLink(RetInfo.Index).Attrs;
-          ParamAttrs |= Sets.getLink(ParamInfo.Index).Attrs;
-          auto MaybeRelation =
-              getIndexRelation(Sets, ParamInfo.Index, RetInfo.Index);
-          if (MaybeRelation.hasValue())
-            AddEdge = true;
-        }
-        if (AddEdge)
-          Output.push_back(
-              Edge{FuncValue, ArgVal, EdgeType::Assign, RetAttrs, ParamAttrs});
-      }
-
-      if (Parameters.size() != Arguments.size())
-        return false;
+      auto &FnInfo = AA.ensureCached(Fn);
+      assert(FnInfo.hasValue());
 
-      /// Adding edges between arguments for arguments that may end up aliasing
-      /// each other. This is necessary for functions such as
-      /// void foo(int** a, int** b) { *a = *b; }
-      /// (Technically, the proper sets for this would be those below
-      /// Arguments[I] and Arguments[X], but our algorithm will produce
-      /// extremely similar, and equally correct, results either way)
-      for (unsigned I = 0, E = Arguments.size(); I != E; ++I) {
-        auto &MainVal = Arguments[I];
-        auto &MainInfo = Parameters[I];
-        auto &MainAttrs = Sets.getLink(MainInfo.Index).Attrs;
-        for (unsigned X = I + 1; X != E; ++X) {
-          auto &SubInfo = Parameters[X];
-          auto &SubVal = Arguments[X];
-          auto &SubAttrs = Sets.getLink(SubInfo.Index).Attrs;
-          auto MaybeRelation =
-              getIndexRelation(Sets, MainInfo.Index, SubInfo.Index);
-
-          if (!MaybeRelation.hasValue())
-            continue;
-
-          Output.push_back(
-              Edge{MainVal, SubVal, EdgeType::Assign, MainAttrs, SubAttrs});
-        }
+      auto &RetParamRelations = FnInfo->getRetParamRelations();
+      for (auto &Relation : RetParamRelations) {
+        auto FromIndex = Relation.From;
+        auto ToIndex = Relation.To;
+        auto FromVal = (FromIndex == 0) ? CS.getInstruction()
+                                        : CS.getArgument(FromIndex - 1);
+        auto ToVal =
+            (ToIndex == 0) ? CS.getInstruction() : CS.getArgument(ToIndex - 1);
+        if (FromVal->getType()->isPointerTy() &&
+            ToVal->getType()->isPointerTy())
+          // Actual arguments must be defined before they are used at callsite.
+          // Therefore by the time we reach here, FromVal and ToVal should
+          // already exist in the graph. We can go ahead and add them directly.
+          Graph.addEdge(FromVal, ToVal, EdgeType::Assign);
       }
     }
 
-    // Commit all edges in Output to CFLGraph
-    for (const auto &Edge : Output) {
-      addEdge(Edge.From, Edge.To, Edge.Weight);
-      Graph.addAttr(Edge.From, Edge.FromAttrs);
-      Graph.addAttr(Edge.To, Edge.ToAttrs);
-    }
-
     return true;
   }
 
@@ -511,7 +428,7 @@ public:
     // Make sure all arguments and return value are added to the graph first
     for (Value *V : CS.args())
       addNode(V);
-    if (!Inst->getType()->isVoidTy())
+    if (Inst->getType()->isPointerTy())
       addNode(Inst);
 
     // Check if Inst is a call to a library function that allocates/deallocates
@@ -526,7 +443,7 @@ public:
     // that we can tack on.
     SmallVector<Function *, 4> Targets;
     if (getPossibleTargets(CS, Targets))
-      if (tryInterproceduralAnalysis(Targets, Inst, CS.args()))
+      if (tryInterproceduralAnalysis(CS, Targets))
         return;
 
     // Because the function is opaque, we need to note that anything
@@ -539,7 +456,7 @@ public:
           Escapes.insert(V);
       }
 
-    if (!Inst->getType()->isVoidTy()) {
+    if (Inst->getType()->isPointerTy()) {
       auto *Fn = CS.getCalledFunction();
       if (Fn == nullptr || !Fn->doesNotAlias(0))
         Graph.addAttr(Inst, AttrUnknown);
@@ -643,8 +560,10 @@ class CFLGraphBuilder {
   void addInstructionToGraph(Instruction &Inst) {
     // We don't want the edges of most "return" instructions, but we *do* want
     // to know what can be returned.
-    if (isa<ReturnInst>(&Inst))
-      ReturnedValues.push_back(&Inst);
+    if (auto RetInst = dyn_cast<ReturnInst>(&Inst))
+      if (auto RetVal = RetInst->getReturnValue())
+        if (RetVal->getType()->isPointerTy())
+          ReturnedValues.push_back(RetVal);
 
     if (!hasUsefulEdges(&Inst))
       return;
@@ -671,12 +590,16 @@ public:
     buildGraphFrom(Fn);
   }
 
-  const CFLGraph &getCFLGraph() { return Graph; }
-  SmallVector<Value *, 4> takeReturnValues() {
-    return std::move(ReturnedValues);
+  const CFLGraph &getCFLGraph() const { return Graph; }
+  const SmallVector<Value *, 4> &getReturnValues() const {
+    return ReturnedValues;
+  }
+  const SmallPtrSet<Value *, 8> &getExternalValues() const {
+    return ExternalValues;
+  }
+  const SmallPtrSet<Value *, 8> &getEscapedValues() const {
+    return EscapedValues;
   }
-  const SmallPtrSet<Value *, 8> &getExternalValues() { return ExternalValues; }
-  const SmallPtrSet<Value *, 8> &getEscapedValues() { return EscapedValues; }
 };
 }
 
@@ -788,6 +711,96 @@ static bool canSkipAddingToSets(Value *V
   return false;
 }
 
+/// Gets whether the sets at Index1 above, below, or equal to the sets at
+/// Index2. Returns None if they are not in the same set chain.
+static Optional<Level> getIndexRelation(const StratifiedSets<Value *> &Sets,
+                                        StratifiedIndex Index1,
+                                        StratifiedIndex Index2) {
+  if (Index1 == Index2)
+    return Level::Same;
+
+  const auto *Current = &Sets.getLink(Index1);
+  while (Current->hasBelow()) {
+    if (Current->Below == Index2)
+      return Level::Below;
+    Current = &Sets.getLink(Current->Below);
+  }
+
+  Current = &Sets.getLink(Index1);
+  while (Current->hasAbove()) {
+    if (Current->Above == Index2)
+      return Level::Above;
+    Current = &Sets.getLink(Current->Above);
+  }
+
+  return None;
+}
+
+CFLAAResult::FunctionInfo::FunctionInfo(Function &Fn,
+                                        const SmallVectorImpl<Value *> &RetVals,
+                                        StratifiedSets<Value *> S)
+    : Sets(std::move(S)) {
+  LLVM_CONSTEXPR unsigned ExpectedMaxArgs = 8;
+
+  // Collect StratifiedInfo for each parameter
+  SmallVector<Optional<StratifiedInfo>, ExpectedMaxArgs> ParamInfos;
+  for (auto &Param : Fn.args()) {
+    if (Param.getType()->isPointerTy())
+      ParamInfos.push_back(Sets.find(&Param));
+    else
+      ParamInfos.push_back(None);
+  }
+  // Collect StratifiedInfo for each return value
+  SmallVector<Optional<StratifiedInfo>, 4> RetInfos;
+  RetInfos.reserve(RetVals.size());
+  for (unsigned I = 0, E = RetVals.size(); I != E; ++I)
+    RetInfos.push_back(Sets.find(RetVals[I]));
+
+  // This summary generation algorithm is n^2. An arbitrary upper-bound of 50
+  // args was selected, so it doesn't take too long in insane cases.
+  if (Fn.arg_size() <= MaxSupportedArgsInSummary) {
+    for (unsigned I = 0, E = ParamInfos.size(); I != E; ++I) {
+      auto &MainInfo = ParamInfos[I];
+      if (!MainInfo)
+        continue;
+
+      // Adding edges between arguments for arguments that may end up aliasing
+      // each other. This is necessary for functions such as
+      // void foo(int** a, int** b) { *a = *b; }
+      // (Technically, the proper sets for this would be those below
+      // Arguments[I] and Arguments[X], but our algorithm will produce
+      // extremely similar, and equally correct, results either way)
+      for (unsigned X = I + 1; X != E; ++X) {
+        auto &SubInfo = ParamInfos[X];
+        if (!SubInfo)
+          continue;
+
+        auto MaybeRelation =
+            getIndexRelation(Sets, MainInfo->Index, SubInfo->Index);
+        if (!MaybeRelation.hasValue())
+          continue;
+
+        RetParamRelations.push_back(ExternalRelation{1 + I, 1 + X});
+      }
+
+      // Adding an edge from argument -> return value for each parameter that
+      // may alias the return value
+      for (unsigned X = 0, XE = RetInfos.size(); X != XE; ++X) {
+        auto &RetInfo = RetInfos[X];
+        if (!RetInfo)
+          continue;
+
+        auto MaybeRelation =
+            getIndexRelation(Sets, MainInfo->Index, RetInfo->Index);
+        if (!MaybeRelation.hasValue())
+          continue;
+
+        RetParamRelations.push_back(ExternalRelation{1 + I, 0});
+      }
+    }
+  }
+}
+
 // Builds the graph + StratifiedSets for a function.
 CFLAAResult::FunctionInfo CFLAAResult::buildSetsFrom(Function *Fn) {
   CFLGraphBuilder GraphBuilder(*this, TLI, *Fn);
@@ -848,7 +861,7 @@ CFLAAResult::FunctionInfo CFLAAResult::b
     SetBuilder.addAttributesBelow(Escape, AttrUnknown);
   }
 
-  return FunctionInfo(SetBuilder.build(), GraphBuilder.takeReturnValues());
+  return FunctionInfo(*Fn, GraphBuilder.getReturnValues(), SetBuilder.build());
 }
 
 void CFLAAResult::scan(Function *Fn) {
@@ -912,7 +925,7 @@ AliasResult CFLAAResult::query(const Mem
   auto &MaybeInfo = ensureCached(Fn);
   assert(MaybeInfo.hasValue());
 
-  auto &Sets = MaybeInfo->Sets;
+  auto &Sets = MaybeInfo->getStratifiedSets();
   auto MaybeA = Sets.find(ValA);
   if (!MaybeA.hasValue())
     return MayAlias;

Modified: llvm/trunk/test/Analysis/CFLAliasAnalysis/basic-interproc.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/basic-interproc.ll?rev=273219&r1=273218&r2=273219&view=diff
==============================================================================
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/basic-interproc.ll (original)
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/basic-interproc.ll Mon Jun 20 18:10:56 2016
@@ -1,22 +1,22 @@
-; This testcase ensures that CFL AA gives conservative answers on variables
-; that involve arguments.
+; This testcase ensures that CFL AA won't be too conservative when trying to do
+; interprocedural analysis on simple callee
 
-; RUN: opt < %s -disable-basicaa -cfl-aa -aa-eval -print-may-aliases -disable-output 2>&1 | FileCheck %s
-; RUN: opt < %s -aa-pipeline=cfl-aa -passes=aa-eval -print-may-aliases -disable-output 2>&1 | FileCheck %s
+; RUN: opt < %s -disable-basicaa -cfl-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+; RUN: opt < %s -aa-pipeline=cfl-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
 
-; CHECK: Function: test2
+; CHECK-LABEL: Function: noop_callee
 ; CHECK: MayAlias: i32* %arg1, i32* %arg2
-define void @test2(i32* %arg1, i32* %arg2) {
+define void @noop_callee(i32* %arg1, i32* %arg2) {
   store i32 0, i32* %arg1
   store i32 0, i32* %arg2
-
   ret void
 }
-
-define void @test() {
+; CHECK-LABEL: Function: test_noop
+; CHECK: NoAlias: i32* %a, i32* %b
+define void @test_noop() {
   %a = alloca i32, align 4
   %b = alloca i32, align 4
-  call void @test2(i32* %a, i32* %b)
+  call void @noop_callee(i32* %a, i32* %b)
 
   ret void
 }

Added: llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-arg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-arg.ll?rev=273219&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-arg.ll (added)
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-arg.ll Mon Jun 20 18:10:56 2016
@@ -0,0 +1,25 @@
+; This testcase ensures that CFL AA answers queries soundly when callee tries 
+; to return one of its parameters
+
+; RUN: opt < %s -disable-basicaa -cfl-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+; RUN: opt < %s -aa-pipeline=cfl-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+; We have to xfail this since @return_arg_callee is treated as an opaque 
+; function, and the anlysis couldn't prove that %b and %c are not aliases 
+; XFAIL: *
+
+define i32* @return_arg_callee(i32* %arg1, i32* %arg2) {
+  ret i32* %arg1
+}
+; CHECK-LABEL: Function: test_return_arg
+; CHECK: NoAlias: i32* %a, i32* %b
+; CHECK: MayAlias: i32* %a, i32* %c
+; CHECK: NoAlias: i32* %b, i32* %c
+define void @test_return_arg() {
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+
+  %c = call i32* @return_arg_callee(i32* %a, i32* %b)
+
+  ret void
+}
\ No newline at end of file

Added: llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-deref-arg-multilevel.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-deref-arg-multilevel.ll?rev=273219&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-deref-arg-multilevel.ll (added)
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-deref-arg-multilevel.ll Mon Jun 20 18:10:56 2016
@@ -0,0 +1,50 @@
+; This testcase ensures that CFL AA answers queries soundly when callee tries 
+; to return the multi-level dereference of one of its parameters
+
+; RUN: opt < %s -disable-basicaa -cfl-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+; RUN: opt < %s -aa-pipeline=cfl-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+; xfail for now due to buggy interproc analysis
+; XFAIL: *
+
+define i32* @return_deref_arg_multilevel_callee(i32*** %arg1) {
+	%deref = load i32**, i32*** %arg1
+	%deref2 = load i32*, i32** %deref
+	ret i32* %deref2
+}
+; CHECK-LABEL: Function: test_return_deref_arg_multilevel
+; CHECK: NoAlias: i32* %a, i32* %b
+; CHECK: MayAlias: i32* %a, i32* %c
+; CHECK: NoAlias: i32* %b, i32* %c
+; CHECK: NoAlias: i32* %c, i32** %p
+; CHECK: NoAlias: i32* %c, i32*** %pp
+; CHECK: MayAlias: i32** %lpp, i32** %p
+; CHECK: NoAlias: i32** %lpp, i32*** %pp
+; CHECK: NoAlias: i32* %c, i32** %lpp
+; CHECK: MayAlias: i32* %a, i32* %lpp_deref
+; CHECK: NoAlias: i32* %b, i32* %lpp_deref
+; CHECK: MayAlias: i32* %lpp_deref, i32** %p
+; CHECK: NoAlias: i32* %lpp_deref, i32*** %pp
+; CHECK: MayAlias: i32* %a, i32* %lp
+; CHECK: NoAlias: i32* %b, i32* %lp
+; CHECK: NoAlias: i32* %lp, i32** %p
+; CHECK: NoAlias: i32* %lp, i32*** %pp
+; CHECK: MayAlias: i32* %c, i32* %lp
+; CHECK: NoAlias: i32* %lp, i32** %lpp
+; CHECK: MayAlias: i32* %lp, i32* %lpp_deref
+define void @test_return_deref_arg_multilevel() {
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+  %p = alloca i32*, align 8
+  %pp = alloca i32**, align 8
+
+  store i32* %a, i32** %p
+  store i32** %p, i32*** %pp
+  %c = call i32* @return_deref_arg_multilevel_callee(i32*** %pp)
+
+  %lpp = load i32**, i32*** %pp
+  %lpp_deref = load i32*, i32** %lpp
+  %lp = load i32*, i32** %p
+
+  ret void
+}
\ No newline at end of file

Added: llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-deref-arg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-deref-arg.ll?rev=273219&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-deref-arg.ll (added)
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-deref-arg.ll Mon Jun 20 18:10:56 2016
@@ -0,0 +1,33 @@
+; This testcase ensures that CFL AA answers queries soundly when callee tries 
+; to return the dereference of one of its parameters
+
+; RUN: opt < %s -disable-basicaa -cfl-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+; RUN: opt < %s -aa-pipeline=cfl-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+; xfail for now due to buggy interproc analysis
+; XFAIL: *
+
+define i32* @return_deref_arg_callee(i32** %arg1) {
+	%deref = load i32*, i32** %arg1
+	ret i32* %deref
+}
+; CHECK-LABEL: Function: test_return_deref_arg
+; CHECK: NoAlias: i32* %a, i32* %b
+; CHECK: MayAlias: i32* %a, i32* %c
+; CHECK: NoAlias: i32* %b, i32* %c
+; CHECK: MayAlias: i32* %a, i32* %lp
+; CHECK: NoAlias: i32* %b, i32* %lp
+; CHECK: NoAlias: i32* %lp, i32** %p
+; CHECK: MayAlias: i32* %c, i32* %lp
+define void @test_return_deref_arg() {
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+  %p = alloca i32*, align 8
+
+  store i32* %a, i32** %p
+  %c = call i32* @return_deref_arg_callee(i32** %p)
+
+  %lp = load i32*, i32** %p
+
+  ret void
+}
\ No newline at end of file

Added: llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-ref-arg-multilevel.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-ref-arg-multilevel.ll?rev=273219&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-ref-arg-multilevel.ll (added)
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-ref-arg-multilevel.ll Mon Jun 20 18:10:56 2016
@@ -0,0 +1,52 @@
+; This testcase ensures that CFL AA answers queries soundly when callee tries 
+; to return the multi-level reference of one of its parameters
+
+; RUN: opt < %s -disable-basicaa -cfl-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+; RUN: opt < %s -aa-pipeline=cfl-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+; xfail for now due to buggy interproc analysis
+; XFAIL: *
+
+declare noalias i8* @malloc(i64)
+
+define i32*** @return_ref_arg_multilevel_callee(i32* %arg1) {
+	%ptr = call noalias i8* @malloc(i64 8)
+	%ptr_cast = bitcast i8* %ptr to i32***
+  %ptr2 = call noalias i8* @malloc(i64 8)
+  %ptr_cast2 = bitcast i8* %ptr2 to i32**
+	store i32* %arg1, i32** %ptr_cast2
+  store i32** %ptr_cast2, i32*** %ptr_cast
+	ret i32*** %ptr_cast
+}
+; CHECK-LABEL: Function: test_return_ref_arg_multilevel
+; CHECK: NoAlias: i32* %a, i32*** %b
+; CHECK: NoAlias: i32** %p, i32*** %b
+; CHECK: NoAlias: i32*** %b, i32*** %pp
+; CHECK: NoAlias: i32* %a, i32** %lb
+; CHECK: NoAlias: i32** %lb, i32** %p
+; CHECK: NoAlias: i32** %lb, i32*** %pp
+; CHECK: NoAlias: i32** %lb, i32*** %b
+; CHECK: MayAlias: i32* %a, i32* %lb_deref
+; CHECK: NoAlias: i32* %lb_deref, i32** %lpp
+; CHECK: MayAlias: i32* %lb_deref, i32* %lpp_deref
+; CHECK: NoAlias: i32* %lpp_deref, i32** %lpp
+; CHECK: MayAlias: i32* %lb_deref, i32* %lp
+; CHECK: NoAlias: i32* %lp, i32** %lpp
+; CHECK: MayAlias: i32* %lp, i32* %lpp_deref
+define void @test_return_ref_arg_multilevel() {
+  %a = alloca i32, align 4
+  %p = alloca i32*, align 8
+  %pp = alloca i32**, align 8
+
+  store i32* %a, i32** %p
+  store i32** %p, i32*** %pp
+  %b = call i32*** @return_ref_arg_multilevel_callee(i32* %a)
+
+  %lb = load i32**, i32*** %b
+  %lb_deref = load i32*, i32** %lb
+  %lpp = load i32**, i32*** %pp
+  %lpp_deref = load i32*, i32** %lpp
+  %lp = load i32*, i32** %p
+
+  ret void
+}
\ No newline at end of file

Added: llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-ref-arg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-ref-arg.ll?rev=273219&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-ref-arg.ll (added)
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-ref-arg.ll Mon Jun 20 18:10:56 2016
@@ -0,0 +1,37 @@
+; This testcase ensures that CFL AA answers queries soundly when callee tries 
+; to return the reference of one of its parameters
+
+; RUN: opt < %s -disable-basicaa -cfl-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+; RUN: opt < %s -aa-pipeline=cfl-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+; xfail for now due to buggy interproc analysis
+; XFAIL: *
+
+declare noalias i8* @malloc(i64)
+
+define i32** @return_ref_arg_callee(i32* %arg1) {
+	%ptr = call noalias i8* @malloc(i64 8)
+	%ptr_cast = bitcast i8* %ptr to i32**
+	store i32* %arg1, i32** %ptr_cast
+	ret i32** %ptr_cast
+}
+; CHECK-LABEL: Function: test_return_ref_arg
+; CHECK: NoAlias: i32** %b, i32** %p
+; CHECK: MayAlias: i32* %a, i32* %lb
+; CHECK: NoAlias: i32* %lb, i32** %p
+; CHECK: NoAlias: i32* %lb, i32** %b
+; CHECK: NoAlias: i32* %lp, i32** %p
+; CHECK: NoAlias: i32* %lp, i32** %b
+; CHECK: MayAlias: i32* %lb, i32* %lp
+define void @test_return_ref_arg() {
+  %a = alloca i32, align 4
+  %p = alloca i32*, align 8
+
+  store i32* %a, i32** %p
+  %b = call i32** @return_ref_arg_callee(i32* %a)
+
+  %lb = load i32*, i32** %b
+  %lp = load i32*, i32** %p
+
+  ret void
+}
\ No newline at end of file

Added: llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-unknown.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-unknown.ll?rev=273219&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-unknown.ll (added)
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-ret-unknown.ll Mon Jun 20 18:10:56 2016
@@ -0,0 +1,27 @@
+; This testcase ensures that CFL AA answers queries soundly when callee tries 
+; to return an unknown pointer
+
+; RUN: opt < %s -disable-basicaa -cfl-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+; RUN: opt < %s -aa-pipeline=cfl-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+; xfail for now due to buggy interproc analysis
+; XFAIL: *
+
+ at g = external global i32
+
+define i32* @return_unknown_callee(i32* %arg1, i32* %arg2) {
+	ret i32* @g
+}
+; CHECK-LABEL: Function: test_return_unknown
+; CHECK: NoAlias: i32* %a, i32* %b
+; CHECK: MayAlias: i32* %c, i32* %x
+; CHECK: NoAlias: i32* %a, i32* %c
+; CHECK: NoAlias: i32* %b, i32* %c
+define void @test_return_unknown(i32* %x) {
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+
+  %c = call i32* @return_unknown_callee(i32* %a, i32* %b)
+
+  ret void
+}
\ No newline at end of file

Added: llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg-multilevel.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg-multilevel.ll?rev=273219&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg-multilevel.ll (added)
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg-multilevel.ll Mon Jun 20 18:10:56 2016
@@ -0,0 +1,49 @@
+; This testcase ensures that CFL AA answers queries soundly when callee tries 
+; to mutate the memory pointed to by its parameters
+
+; RUN: opt < %s -disable-basicaa -cfl-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+; RUN: opt < %s -aa-pipeline=cfl-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+; xfail for now due to buggy interproc analysis
+; XFAIL: *
+
+declare noalias i8* @malloc(i64)
+
+define void @store_arg_multilevel_callee(i32*** %arg1, i32* %arg2) {
+  %ptr = call noalias i8* @malloc(i64 8)
+  %ptr_cast = bitcast i8* %ptr to i32**
+	store i32* %arg2, i32** %ptr_cast
+  store i32** %ptr_cast, i32*** %arg1
+	ret void
+}
+; CHECK-LABEL: Function: test_store_arg_multilevel
+; CHECK: NoAlias: i32* %a, i32* %b
+; CHECK: NoAlias: i32* %a, i32** %lpp
+; CHECK: NoAlias: i32* %b, i32** %lpp
+; CHECK: MayAlias: i32** %lpp, i32** %p
+; CHECK: MayAlias: i32* %a, i32* %lpp_deref
+; CHECK: MayAlias: i32* %b, i32* %lpp_deref
+; CHECK: NoAlias: i32* %lpp_deref, i32** %p
+; CHECK: NoAlias: i32* %lpp_deref, i32*** %pp
+; CHECK: NoAlias: i32* %lpp_deref, i32** %lpp
+; CHECK: MayAlias: i32* %a, i32* %lp
+; CHECK: NoAlias: i32* %b, i32* %lp
+; CHECK: NoAlias: i32* %lp, i32*** %pp
+; CHECK: NoAlias: i32* %lp, i32** %lpp
+; CHECK: MayAlias: i32* %lp, i32* %lpp_deref
+define void @test_store_arg_multilevel() {
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+  %p = alloca i32*, align 8
+  %pp = alloca i32**, align 8
+
+  store i32* %a, i32** %p
+  store i32** %p, i32*** %pp
+  call void @store_arg_multilevel_callee(i32*** %pp, i32* %b)
+
+  %lpp = load i32**, i32*** %pp
+  %lpp_deref = load i32*, i32** %lpp
+  %lp = load i32*, i32** %p
+
+  ret void
+}
\ No newline at end of file

Added: llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg-unknown.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg-unknown.ll?rev=273219&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg-unknown.ll (added)
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg-unknown.ll Mon Jun 20 18:10:56 2016
@@ -0,0 +1,35 @@
+; This testcase ensures that CFL AA answers queries soundly when callee tries 
+; to mutate the memory pointed to by its parameters
+
+; RUN: opt < %s -disable-basicaa -cfl-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+; RUN: opt < %s -aa-pipeline=cfl-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+; xfail for now due to buggy interproc analysis
+; XFAIL: *
+
+ at g = external global i32
+
+define void @store_arg_unknown_callee(i32** %arg1) {
+	store i32* @g, i32** %arg1
+	ret void
+}
+; CHECK-LABEL: Function: test_store_arg_unknown
+; CHECK: NoAlias: i32* %x, i32** %p
+; CHECK: NoAlias: i32* %a, i32** %p
+; CHECK: NoAlias: i32* %b, i32** %p
+; CHECK: MayAlias: i32* %lp, i32* %x
+; CHECK: MayAlias: i32* %a, i32* %lp
+; CHECK: NoAlias: i32* %b, i32* %lp
+; CHECK: MayAlias: 32* %lp, i32** %p
+define void @test_store_arg_unknown(i32* %x) {
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+  %p = alloca i32*, align 8
+
+  store i32* %a, i32** %p
+  call void @store_arg_unknown_callee(i32** %p)
+
+  %lp = load i32*, i32** %p
+
+  ret void
+}
\ No newline at end of file

Added: llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg.ll?rev=273219&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg.ll (added)
+++ llvm/trunk/test/Analysis/CFLAliasAnalysis/interproc-store-arg.ll Mon Jun 20 18:10:56 2016
@@ -0,0 +1,37 @@
+; This testcase ensures that CFL AA answers queries soundly when callee tries 
+; to mutate the memory pointed to by its parameters
+
+; RUN: opt < %s -disable-basicaa -cfl-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+; RUN: opt < %s -aa-pipeline=cfl-aa -passes=aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+; xfail for now due to buggy interproc analysis
+; XFAIL: *
+
+define void @store_arg_callee(i32** %arg1, i32* %arg2) {
+	store i32* %arg2, i32** %arg1
+	ret void
+}
+; CHECK-LABEL: Function: test_store_arg
+; CHECK: NoAlias: i32* %a, i32* %b
+; CHECK: NoAlias: i32* %a, i32** %p
+; CHECK: NoAlias: i32* %b, i32** %p
+; CHECK: MayAlias: i32* %a, i32* %lp
+; CHECK: MayAlias: i32* %b, i32* %lp
+; CHECK: NoAlias: i32* %a, i32* %lq
+; CHECK: MayAlias: i32* %b, i32* %lq
+; CHECK: NoAlias: i32* %lp, i32* %lq
+define void @test_store_arg() {
+  %a = alloca i32, align 4
+  %b = alloca i32, align 4
+  %p = alloca i32*, align 8
+  %q = alloca i32*, align 8
+
+  store i32* %a, i32** %p
+  store i32* %b, i32** %q
+  call void @store_arg_callee(i32** %p, i32* %b)
+
+  %lp = load i32*, i32** %p
+  %lq = load i32*, i32** %q
+
+  ret void
+}
\ No newline at end of file




More information about the llvm-commits mailing list