]> granicus.if.org Git - llvm/commitdiff
[CFLAA] Tag arguments as escaped instead of unknown.
authorGeorge Burgess IV <george.burgess.iv@gmail.com>
Tue, 14 Jun 2016 18:12:28 +0000 (18:12 +0000)
committerGeorge Burgess IV <george.burgess.iv@gmail.com>
Tue, 14 Jun 2016 18:12:28 +0000 (18:12 +0000)
This patch also includes some refactoring.

Prior to this patch, we tagged all CFLAA attributes as unknown. This is
suboptimal, since it meant that any Value used as an argument would be
considered to alias any other Value that existed.

Now that we have the machinery to tag sets below the set for an
arbitrary value with attributes, it's okay to be less conservative with
arguments. (Specifically, we still tag the set under an argument with
unknown).

Patch by Jia Chen.

Differential Revision: http://reviews.llvm.org/D21262

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@272690 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/CFLAliasAnalysis.cpp
lib/Analysis/StratifiedSets.h
test/Analysis/CFLAliasAnalysis/attr-escape.ll
test/Analysis/CFLAliasAnalysis/opaque-call-alias.ll
test/Analysis/CFLAliasAnalysis/va.ll

index 90564037777aee1b8d3680c5cd5993be88101bc7..8d88986ac19904a91707c2ad42db8628a3fe8aae 100644 (file)
@@ -80,15 +80,7 @@ static Optional<Function *> parentFunctionOfValue(Value *);
 /// Returns possible functions called by the Inst* into the given
 /// SmallVectorImpl. Returns true if targets found, false otherwise. This is
 /// templated so we can use it with CallInsts and InvokeInsts.
-template <typename Inst>
-static bool getPossibleTargets(Inst *, SmallVectorImpl<Function *> &);
-
-/// Some instructions need to have their users tracked. Instructions like
-/// `add` require you to get the users of the Instruction* itself, other
-/// instructions like `store` require you to get the users of the first
-/// operand. This function gets the "proper" value to track for each
-/// type of instruction we support.
-static Optional<Value *> getTargetValue(Instruction *);
+static bool getPossibleTargets(CallSite, SmallVectorImpl<Function *> &);
 
 const StratifiedIndex StratifiedLink::SetSentinel =
     std::numeric_limits<StratifiedIndex>::max();
@@ -135,36 +127,126 @@ enum class EdgeType {
   Reference
 };
 
-// \brief Encodes the notion of a "use"
-struct Edge {
-  /// Which value the edge is coming from
-  Value *From;
+/// The Program Expression Graph (PEG) of CFL analysis
+class CFLGraph {
+  typedef Value *Node;
+
+  struct Edge {
+    StratifiedAttrs Attr;
+    EdgeType Type;
+    Node Other;
+  };
+
+  typedef std::vector<Edge> EdgeList;
+  typedef DenseMap<Node, EdgeList> NodeMap;
+  NodeMap NodeImpls;
+
+  // Gets the inverse of a given EdgeType.
+  static EdgeType flipWeight(EdgeType Initial) {
+    switch (Initial) {
+    case EdgeType::Assign:
+      return EdgeType::Assign;
+    case EdgeType::Dereference:
+      return EdgeType::Reference;
+    case EdgeType::Reference:
+      return EdgeType::Dereference;
+    }
+    llvm_unreachable("Incomplete coverage of EdgeType enum");
+  }
+
+  const EdgeList *getNode(Node N) const {
+    auto Itr = NodeImpls.find(N);
+    if (Itr == NodeImpls.end())
+      return nullptr;
+    return &Itr->second;
+  }
+  EdgeList *getNode(Node N) {
+    auto Itr = NodeImpls.find(N);
+    if (Itr == NodeImpls.end())
+      return nullptr;
+    return &Itr->second;
+  }
+
+  static Node nodeDeref(const NodeMap::value_type &P) { return P.first; }
+  typedef std::pointer_to_unary_function<const NodeMap::value_type &, Node>
+      NodeDerefFun;
 
-  /// Which value the edge is pointing to
-  Value *To;
+public:
+  typedef EdgeList::const_iterator const_edge_iterator;
+  typedef mapped_iterator<NodeMap::const_iterator, NodeDerefFun>
+      const_node_iterator;
+
+  bool addNode(Node N) {
+    return NodeImpls.insert(std::make_pair(N, EdgeList())).second;
+  }
 
-  /// Edge weight
-  EdgeType Weight;
+  void addEdge(Node From, Node To, EdgeType Type,
+               StratifiedAttrs Attr = StratifiedAttrs()) {
+    auto FromEdges = getNode(From);
+    assert(FromEdges != nullptr);
+    auto ToEdges = getNode(To);
+    assert(ToEdges != nullptr);
 
-  /// Whether we aliased any external values along the way that may be
-  /// invisible to the analysis (i.e. landingpad for exceptions, calls for
-  /// interprocedural analysis, etc.)
-  StratifiedAttrs AdditionalAttrs;
+    FromEdges->push_back(Edge{Attr, Type, To});
+    ToEdges->push_back(Edge{Attr, flipWeight(Type), From});
+  }
 
-  Edge(Value *From, Value *To, EdgeType W, StratifiedAttrs A)
-      : From(From), To(To), Weight(W), AdditionalAttrs(A) {}
+  iterator_range<const_edge_iterator> edgesFor(Node N) const {
+    auto Edges = getNode(N);
+    assert(Edges != nullptr);
+    return make_range(Edges->begin(), Edges->end());
+  }
+
+  iterator_range<const_node_iterator> nodes() const {
+    return make_range<const_node_iterator>(
+        map_iterator(NodeImpls.begin(), NodeDerefFun(nodeDeref)),
+        map_iterator(NodeImpls.end(), NodeDerefFun(nodeDeref)));
+  }
+
+  bool empty() const { return NodeImpls.empty(); }
+  std::size_t size() const { return NodeImpls.size(); }
 };
 
 /// Gets the edges our graph should have, based on an Instruction*
 class GetEdgesVisitor : public InstVisitor<GetEdgesVisitor, void> {
   CFLAAResult &AA;
-  SmallVectorImpl<Edge> &Output;
   const TargetLibraryInfo &TLI;
 
+  CFLGraph &Graph;
+  SmallPtrSetImpl<Value *> &Externals;
+  SmallPtrSetImpl<Value *> &Escapes;
+
+  static bool hasUsefulEdges(ConstantExpr *CE) {
+    // ConstantExpr doesn't have terminators, invokes, or fences, so only needs
+    // to check for compares.
+    return CE->getOpcode() != Instruction::ICmp &&
+           CE->getOpcode() != Instruction::FCmp;
+  }
+
+  void addNode(Value *Val) {
+    if (!Graph.addNode(Val))
+      return;
+
+    if (isa<GlobalValue>(Val))
+      Externals.insert(Val);
+    else if (auto CExpr = dyn_cast<ConstantExpr>(Val))
+      if (hasUsefulEdges(CExpr))
+        visitConstantExpr(CExpr);
+  }
+
+  void addEdge(Value *From, Value *To, EdgeType Type, StratifiedAttrs Attr) {
+    addNode(From);
+    if (To != From)
+      addNode(To);
+    Graph.addEdge(From, To, Type, Attr);
+  }
+
 public:
-  GetEdgesVisitor(CFLAAResult &AA, SmallVectorImpl<Edge> &Output,
-                  const TargetLibraryInfo &TLI)
-      : AA(AA), Output(Output), TLI(TLI) {}
+  GetEdgesVisitor(CFLAAResult &AA, const TargetLibraryInfo &TLI,
+                  CFLGraph &Graph, SmallPtrSetImpl<Value *> &Externals,
+                  SmallPtrSetImpl<Value *> &Escapes)
+      : AA(AA), TLI(TLI), Graph(Graph), Externals(Externals), Escapes(Escapes) {
+  }
 
   void visitInstruction(Instruction &) {
     llvm_unreachable("Unsupported instruction encountered");
@@ -172,46 +254,46 @@ public:
 
   void visitPtrToIntInst(PtrToIntInst &Inst) {
     auto *Ptr = Inst.getOperand(0);
-    Output.push_back(Edge(Ptr, &Inst, EdgeType::Assign, AttrEscaped));
+    addEdge(Ptr, &Inst, EdgeType::Assign, AttrEscaped);
   }
 
   void visitIntToPtrInst(IntToPtrInst &Inst) {
     auto *Ptr = &Inst;
-    Output.push_back(Edge(Ptr, Ptr, EdgeType::Assign, AttrUnknown));
+    addEdge(Ptr, Ptr, EdgeType::Assign, AttrUnknown);
   }
 
   void visitCastInst(CastInst &Inst) {
-    Output.push_back(
-        Edge(&Inst, Inst.getOperand(0), EdgeType::Assign, AttrNone));
+    auto *Src = Inst.getOperand(0);
+    addEdge(Src, &Inst, EdgeType::Assign, AttrNone);
   }
 
   void visitBinaryOperator(BinaryOperator &Inst) {
     auto *Op1 = Inst.getOperand(0);
     auto *Op2 = Inst.getOperand(1);
-    Output.push_back(Edge(&Inst, Op1, EdgeType::Assign, AttrNone));
-    Output.push_back(Edge(&Inst, Op2, EdgeType::Assign, AttrNone));
+    addEdge(Op1, &Inst, EdgeType::Assign, AttrNone);
+    addEdge(Op2, &Inst, EdgeType::Assign, AttrNone);
   }
 
   void visitAtomicCmpXchgInst(AtomicCmpXchgInst &Inst) {
     auto *Ptr = Inst.getPointerOperand();
     auto *Val = Inst.getNewValOperand();
-    Output.push_back(Edge(Ptr, Val, EdgeType::Dereference, AttrNone));
+    addEdge(Ptr, Val, EdgeType::Dereference, AttrNone);
   }
 
   void visitAtomicRMWInst(AtomicRMWInst &Inst) {
     auto *Ptr = Inst.getPointerOperand();
     auto *Val = Inst.getValOperand();
-    Output.push_back(Edge(Ptr, Val, EdgeType::Dereference, AttrNone));
+    addEdge(Ptr, Val, EdgeType::Dereference, AttrNone);
   }
 
   void visitPHINode(PHINode &Inst) {
     for (Value *Val : Inst.incoming_values())
-      Output.push_back(Edge(&Inst, Val, EdgeType::Assign, AttrNone));
+      addEdge(Val, &Inst, EdgeType::Assign, AttrNone);
   }
 
   void visitGetElementPtrInst(GetElementPtrInst &Inst) {
     auto *Op = Inst.getPointerOperand();
-    Output.push_back(Edge(&Inst, Op, EdgeType::Assign, AttrNone));
+    addEdge(Op, &Inst, EdgeType::Assign, AttrNone);
   }
 
   void visitSelectInst(SelectInst &Inst) {
@@ -221,23 +303,23 @@ public:
     // simply as a result of being the condition of a select.
 
     auto *TrueVal = Inst.getTrueValue();
-    Output.push_back(Edge(&Inst, TrueVal, EdgeType::Assign, AttrNone));
     auto *FalseVal = Inst.getFalseValue();
-    Output.push_back(Edge(&Inst, FalseVal, EdgeType::Assign, AttrNone));
+    addEdge(TrueVal, &Inst, EdgeType::Assign, AttrNone);
+    addEdge(FalseVal, &Inst, EdgeType::Assign, AttrNone);
   }
 
-  void visitAllocaInst(AllocaInst &) {}
+  void visitAllocaInst(AllocaInst &Inst) { Graph.addNode(&Inst); }
 
   void visitLoadInst(LoadInst &Inst) {
     auto *Ptr = Inst.getPointerOperand();
     auto *Val = &Inst;
-    Output.push_back(Edge(Val, Ptr, EdgeType::Reference, AttrNone));
+    addEdge(Val, Ptr, EdgeType::Reference, AttrNone);
   }
 
   void visitStoreInst(StoreInst &Inst) {
     auto *Ptr = Inst.getPointerOperand();
     auto *Val = Inst.getValueOperand();
-    Output.push_back(Edge(Ptr, Val, EdgeType::Dereference, AttrNone));
+    addEdge(Ptr, Val, EdgeType::Dereference, AttrNone);
   }
 
   void visitVAArgInst(VAArgInst &Inst) {
@@ -248,7 +330,7 @@ public:
     // For now, we'll handle this like a landingpad instruction (by placing the
     // result in its own group, and having that group alias externals).
     auto *Val = &Inst;
-    Output.push_back(Edge(Val, Val, EdgeType::Assign, AttrUnknown));
+    addEdge(Val, Val, EdgeType::Assign, AttrUnknown);
   }
 
   static bool isFunctionExternal(Function *Fn) {
@@ -280,6 +362,23 @@ public:
     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 (i.e. landingpad for exceptions, calls for
+    // interprocedural analysis, etc.)
+    StratifiedAttrs AdditionalAttrs;
+  };
+
   bool
   tryInterproceduralAnalysis(const SmallVectorImpl<Function *> &Fns,
                              Value *FuncValue,
@@ -302,6 +401,7 @@ public:
         return false;
     }
 
+    SmallVector<Edge, 8> Output;
     SmallVector<Value *, ExpectedMaxArgs> Arguments(Args.begin(), Args.end());
     SmallVector<StratifiedInfo, ExpectedMaxArgs> Parameters;
     for (auto *Fn : Fns) {
@@ -342,7 +442,7 @@ public:
         }
         if (AddEdge)
           Output.push_back(
-              Edge(FuncValue, ArgVal, EdgeType::Assign, Externals));
+              Edge{FuncValue, ArgVal, EdgeType::Assign, Externals});
       }
 
       if (Parameters.size() != Arguments.size())
@@ -369,53 +469,57 @@ public:
             continue;
 
           auto NewAttrs = SubAttrs | MainAttrs;
-          Output.push_back(Edge(MainVal, SubVal, EdgeType::Assign, NewAttrs));
+          Output.push_back(Edge{MainVal, SubVal, EdgeType::Assign, NewAttrs});
         }
       }
     }
+
+    // Commit all edges in Output to CFLGraph
+    for (const auto &Edge : Output)
+      addEdge(Edge.From, Edge.To, Edge.Weight, Edge.AdditionalAttrs);
+
     return true;
   }
 
-  template <typename InstT> void visitCallLikeInst(InstT &Inst) {
+  void visitCallSite(CallSite CS) {
+    auto Inst = CS.getInstruction();
+
+    // Make sure all arguments and return value are added to the graph first
+    for (Value *V : CS.args())
+      addNode(V);
+    if (!Inst->getType()->isVoidTy())
+      addNode(Inst);
+
     // Check if Inst is a call to a library function that allocates/deallocates
     // on the heap. Those kinds of functions do not introduce any aliases.
     // TODO: address other common library functions such as realloc(), strdup(),
     // etc.
-    if (isMallocLikeFn(&Inst, &TLI) || isCallocLikeFn(&Inst, &TLI)) {
-      Output.push_back(Edge(&Inst, &Inst, EdgeType::Assign, AttrNone));
+    if (isMallocLikeFn(Inst, &TLI) || isCallocLikeFn(Inst, &TLI) ||
+        isFreeCall(Inst, &TLI))
       return;
-    } else if (isFreeCall(&Inst, &TLI)) {
-      assert(Inst.getNumArgOperands() == 1);
-      auto argVal = Inst.arg_begin()->get();
-      Output.push_back(Edge(argVal, argVal, EdgeType::Assign, AttrNone));
-      return;
-    }
 
     // TODO: Add support for noalias args/all the other fun function attributes
     // that we can tack on.
     SmallVector<Function *, 4> Targets;
-    if (getPossibleTargets(&Inst, Targets)) {
-      if (tryInterproceduralAnalysis(Targets, &Inst, Inst.arg_operands()))
+    if (getPossibleTargets(CS, Targets))
+      if (tryInterproceduralAnalysis(Targets, Inst, CS.args()))
         return;
-      // Cleanup from interprocedural analysis
-      Output.clear();
-    }
 
     // Because the function is opaque, we need to note that anything
-    // could have happened to the arguments, and that the result could alias
-    // just about anything, too.
-    // The goal of the loop is in part to unify many Values into one set, so we
-    // don't care if the function is void there.
-    for (Value *V : Inst.arg_operands())
-      Output.push_back(Edge(&Inst, V, EdgeType::Assign, AttrUnknown));
-    if (Inst.getNumArgOperands() == 0 &&
-        Inst.getType() != Type::getVoidTy(Inst.getContext()))
-      Output.push_back(Edge(&Inst, &Inst, EdgeType::Assign, AttrUnknown));
-  }
-
-  void visitCallInst(CallInst &Inst) { visitCallLikeInst(Inst); }
+    // could have happened to the arguments (unless the function is marked
+    // readonly or readnone), and that the result could alias just about
+    // anything, too (unless the result is marked noalias).
+    if (!CS.onlyReadsMemory())
+      for (Value *V : CS.args()) {
+        Escapes.insert(V);
+      }
 
-  void visitInvokeInst(InvokeInst &Inst) { visitCallLikeInst(Inst); }
+    if (!Inst->getType()->isVoidTy()) {
+      auto *Fn = CS.getCalledFunction();
+      if (Fn == nullptr || !Fn->doesNotAlias(0))
+        addEdge(Inst, Inst, EdgeType::Assign, AttrUnknown);
+    }
+  }
 
   /// Because vectors/aggregates are immutable and unaddressable, there's
   /// nothing we can do to coax a value out of them, other than calling
@@ -424,40 +528,40 @@ public:
   void visitExtractElementInst(ExtractElementInst &Inst) {
     auto *Ptr = Inst.getVectorOperand();
     auto *Val = &Inst;
-    Output.push_back(Edge(Val, Ptr, EdgeType::Reference, AttrNone));
+    addEdge(Val, Ptr, EdgeType::Reference, AttrNone);
   }
 
   void visitInsertElementInst(InsertElementInst &Inst) {
     auto *Vec = Inst.getOperand(0);
     auto *Val = Inst.getOperand(1);
-    Output.push_back(Edge(&Inst, Vec, EdgeType::Assign, AttrNone));
-    Output.push_back(Edge(&Inst, Val, EdgeType::Dereference, AttrNone));
+    addEdge(Vec, &Inst, EdgeType::Assign, AttrNone);
+    addEdge(&Inst, Val, EdgeType::Dereference, AttrNone);
   }
 
   void visitLandingPadInst(LandingPadInst &Inst) {
     // Exceptions come from "nowhere", from our analysis' perspective.
     // So we place the instruction its own group, noting that said group may
     // alias externals
-    Output.push_back(Edge(&Inst, &Inst, EdgeType::Assign, AttrUnknown));
+    addEdge(&Inst, &Inst, EdgeType::Assign, AttrUnknown);
   }
 
   void visitInsertValueInst(InsertValueInst &Inst) {
     auto *Agg = Inst.getOperand(0);
     auto *Val = Inst.getOperand(1);
-    Output.push_back(Edge(&Inst, Agg, EdgeType::Assign, AttrNone));
-    Output.push_back(Edge(&Inst, Val, EdgeType::Dereference, AttrNone));
+    addEdge(Agg, &Inst, EdgeType::Assign, AttrNone);
+    addEdge(&Inst, Val, EdgeType::Dereference, AttrNone);
   }
 
   void visitExtractValueInst(ExtractValueInst &Inst) {
     auto *Ptr = Inst.getAggregateOperand();
-    Output.push_back(Edge(&Inst, Ptr, EdgeType::Reference, AttrNone));
+    addEdge(&Inst, Ptr, EdgeType::Reference, AttrNone);
   }
 
   void visitShuffleVectorInst(ShuffleVectorInst &Inst) {
     auto *From1 = Inst.getOperand(0);
     auto *From2 = Inst.getOperand(1);
-    Output.push_back(Edge(&Inst, From1, EdgeType::Assign, AttrNone));
-    Output.push_back(Edge(&Inst, From2, EdgeType::Assign, AttrNone));
+    addEdge(From1, &Inst, EdgeType::Assign, AttrNone);
+    addEdge(From2, &Inst, EdgeType::Assign, AttrNone);
   }
 
   void visitConstantExpr(ConstantExpr *CE) {
@@ -474,115 +578,6 @@ public:
   }
 };
 
-/// For a given instruction, we need to know which Value* to get the
-/// users of in order to build our graph. In some cases (i.e. add),
-/// we simply need the Instruction*. In other cases (i.e. store),
-/// finding the users of the Instruction* is useless; we need to find
-/// the users of the first operand. This handles determining which
-/// value to follow for us.
-///
-/// Note: we *need* to keep this in sync with GetEdgesVisitor. Add
-/// something to GetEdgesVisitor, add it here -- remove something from
-/// GetEdgesVisitor, remove it here.
-class GetTargetValueVisitor
-    : public InstVisitor<GetTargetValueVisitor, Value *> {
-public:
-  Value *visitInstruction(Instruction &Inst) { return &Inst; }
-
-  Value *visitStoreInst(StoreInst &Inst) { return Inst.getPointerOperand(); }
-
-  Value *visitAtomicCmpXchgInst(AtomicCmpXchgInst &Inst) {
-    return Inst.getPointerOperand();
-  }
-
-  Value *visitAtomicRMWInst(AtomicRMWInst &Inst) {
-    return Inst.getPointerOperand();
-  }
-
-  Value *visitInsertElementInst(InsertElementInst &Inst) {
-    return Inst.getOperand(0);
-  }
-
-  Value *visitInsertValueInst(InsertValueInst &Inst) {
-    return Inst.getAggregateOperand();
-  }
-};
-
-/// The Program Expression Graph (PEG) of CFL analysis
-class CFLGraph {
-  typedef Value *Node;
-
-  struct Edge {
-    StratifiedAttrs Attr;
-    EdgeType Type;
-    Node Other;
-  };
-
-  typedef std::vector<Edge> EdgeList;
-  typedef DenseMap<Node, EdgeList> NodeMap;
-  NodeMap NodeImpls;
-
-  // Gets the inverse of a given EdgeType.
-  static EdgeType flipWeight(EdgeType Initial) {
-    switch (Initial) {
-    case EdgeType::Assign:
-      return EdgeType::Assign;
-    case EdgeType::Dereference:
-      return EdgeType::Reference;
-    case EdgeType::Reference:
-      return EdgeType::Dereference;
-    }
-    llvm_unreachable("Incomplete coverage of EdgeType enum");
-  }
-
-  const EdgeList *getNode(Node N) const {
-    auto Itr = NodeImpls.find(N);
-    if (Itr == NodeImpls.end())
-      return nullptr;
-    return &Itr->second;
-  }
-  EdgeList &getOrCreateNode(Node N) { return NodeImpls[N]; }
-
-  static Node nodeDeref(const NodeMap::value_type &P) { return P.first; }
-  typedef std::pointer_to_unary_function<const NodeMap::value_type &, Node>
-      NodeDerefFun;
-
-public:
-  typedef EdgeList::const_iterator const_edge_iterator;
-  typedef mapped_iterator<NodeMap::const_iterator, NodeDerefFun>
-      const_node_iterator;
-
-  void addNode(Node N) { getOrCreateNode(N); }
-
-  void addEdge(Node From, Node To, EdgeType Type,
-               StratifiedAttrs Attr = StratifiedAttrs()) {
-
-    // We can't getOrCreateNode() twice in a row here since the second call may
-    // invalidate the reference returned from the first call
-    getOrCreateNode(From);
-    auto &ToEdges = getOrCreateNode(To);
-    auto &FromEdges = getOrCreateNode(From);
-
-    FromEdges.push_back(Edge{Attr, Type, To});
-    ToEdges.push_back(Edge{Attr, flipWeight(Type), From});
-  }
-
-  iterator_range<const_edge_iterator> edgesFor(Node N) const {
-    auto Edges = getNode(N);
-    assert(Edges != nullptr);
-    return make_range(Edges->begin(), Edges->end());
-  }
-
-  iterator_range<const_node_iterator> nodes() const {
-    return make_range<const_node_iterator>(
-        map_iterator(NodeImpls.begin(), NodeDerefFun(nodeDeref)),
-        map_iterator(NodeImpls.end(), NodeDerefFun(nodeDeref)));
-  }
-
-  bool empty() const { return NodeImpls.empty(); }
-  std::size_t size() const { return NodeImpls.size(); }
-};
-
 class CFLGraphBuilder {
   // Input of the builder
   CFLAAResult &Analysis;
@@ -593,6 +588,8 @@ class CFLGraphBuilder {
   SmallVector<Value *, 4> ReturnedValues;
 
   // Auxiliary structures used by the builder
+  SmallPtrSet<Value *, 8> ExternalValues;
+  SmallPtrSet<Value *, 8> EscapedValues;
 
   // Helper functions
 
@@ -605,67 +602,9 @@ class CFLGraphBuilder {
            !IsNonInvokeTerminator;
   }
 
-  static bool hasUsefulEdges(ConstantExpr *CE) {
-    // ConstantExpr doesn't have terminators, invokes, or fences, so only needs
-    // to check for compares.
-    return CE->getOpcode() != Instruction::ICmp &&
-           CE->getOpcode() != Instruction::FCmp;
-  }
-
-  // Gets edges of the given Instruction*, writing them to the SmallVector*.
-  void argsToEdges(Instruction *Inst, SmallVectorImpl<Edge> &Output) {
-    assert(hasUsefulEdges(Inst) &&
-           "Expected instructions to have 'useful' edges");
-    GetEdgesVisitor v(Analysis, Output, TLI);
-    v.visit(Inst);
-  }
-
-  // Gets edges of the given ConstantExpr*, writing them to the SmallVector*.
-  void argsToEdges(ConstantExpr *CE, SmallVectorImpl<Edge> &Output) {
-    assert(hasUsefulEdges(CE) &&
-           "Expected constant expr to have 'useful' edges");
-    GetEdgesVisitor v(Analysis, Output, TLI);
-    v.visitConstantExpr(CE);
-  }
-
-  // Gets the edges of a ConstantExpr as if it was an Instruction. This function
-  // also acts on any nested ConstantExprs, adding the edges of those to the
-  // given SmallVector as well.
-  void constexprToEdges(ConstantExpr &CExprToCollapse,
-                        SmallVectorImpl<Edge> &Results) {
-    SmallVector<ConstantExpr *, 4> Worklist;
-    Worklist.push_back(&CExprToCollapse);
-
-    SmallVector<Edge, 8> ConstexprEdges;
-    SmallPtrSet<ConstantExpr *, 4> Visited;
-    while (!Worklist.empty()) {
-      auto *CExpr = Worklist.pop_back_val();
-
-      if (!hasUsefulEdges(CExpr))
-        continue;
-
-      ConstexprEdges.clear();
-      argsToEdges(CExpr, ConstexprEdges);
-      for (auto &Edge : ConstexprEdges) {
-        if (auto *Nested = dyn_cast<ConstantExpr>(Edge.From))
-          if (Visited.insert(Nested).second)
-            Worklist.push_back(Nested);
-
-        if (auto *Nested = dyn_cast<ConstantExpr>(Edge.To))
-          if (Visited.insert(Nested).second)
-            Worklist.push_back(Nested);
-      }
-
-      Results.append(ConstexprEdges.begin(), ConstexprEdges.end());
-    }
-  }
-
-  // Builds the graph needed for constructing the StratifiedSets for the given
-  // function
-  void buildGraphFrom(Function &Fn) {
-    for (auto &Bb : Fn.getBasicBlockList())
-      for (auto &Inst : Bb.getInstList())
-        addInstructionToGraph(Inst);
+  void addArgumentToGraph(Argument &Arg) {
+    Graph.addNode(&Arg);
+    ExternalValues.insert(&Arg);
   }
 
   // Given an Instruction, this will add it to the graph, along with any
@@ -683,37 +622,19 @@ class CFLGraphBuilder {
     if (!hasUsefulEdges(&Inst))
       return;
 
-    SmallVector<Edge, 8> Edges;
-    argsToEdges(&Inst, Edges);
-
-    // In the case of an unused alloca (or similar), edges may be empty. Note
-    // that it exists so we can potentially answer NoAlias.
-    if (Edges.empty()) {
-      auto MaybeVal = getTargetValue(&Inst);
-      assert(MaybeVal.hasValue());
-      auto *Target = *MaybeVal;
-      Graph.addNode(Target);
-      return;
-    }
+    GetEdgesVisitor(Analysis, TLI, Graph, ExternalValues, EscapedValues)
+        .visit(Inst);
+  }
 
-    auto addEdgeToGraph = [this](const Edge &E) {
-      Graph.addEdge(E.From, E.To, E.Weight, E.AdditionalAttrs);
-    };
-
-    SmallVector<ConstantExpr *, 4> ConstantExprs;
-    for (const Edge &E : Edges) {
-      addEdgeToGraph(E);
-      if (auto *Constexpr = dyn_cast<ConstantExpr>(E.To))
-        ConstantExprs.push_back(Constexpr);
-      if (auto *Constexpr = dyn_cast<ConstantExpr>(E.From))
-        ConstantExprs.push_back(Constexpr);
-    }
+  // Builds the graph needed for constructing the StratifiedSets for the given
+  // function
+  void buildGraphFrom(Function &Fn) {
+    for (auto &Bb : Fn.getBasicBlockList())
+      for (auto &Inst : Bb.getInstList())
+        addInstructionToGraph(Inst);
 
-    for (ConstantExpr *CE : ConstantExprs) {
-      Edges.clear();
-      constexprToEdges(*CE, Edges);
-      std::for_each(Edges.begin(), Edges.end(), addEdgeToGraph);
-    }
+    for (auto &Arg : Fn.args())
+      addArgumentToGraph(Arg);
   }
 
 public:
@@ -727,6 +648,8 @@ public:
   SmallVector<Value *, 4> takeReturnValues() {
     return std::move(ReturnedValues);
   }
+  const SmallPtrSet<Value *, 8> &getExternalValues() { return ExternalValues; }
+  const SmallPtrSet<Value *, 8> &getEscapedValues() { return EscapedValues; }
 };
 }
 
@@ -766,10 +689,9 @@ static Optional<Function *> parentFunctionOfValue(Value *Val) {
   return None;
 }
 
-template <typename Inst>
-static bool getPossibleTargets(Inst *Call,
+static bool getPossibleTargets(CallSite CS,
                                SmallVectorImpl<Function *> &Output) {
-  if (auto *Fn = Call->getCalledFunction()) {
+  if (auto *Fn = CS.getCalledFunction()) {
     Output.push_back(Fn);
     return true;
   }
@@ -779,11 +701,6 @@ static bool getPossibleTargets(Inst *Call,
   return false;
 }
 
-static Optional<Value *> getTargetValue(Instruction *Inst) {
-  GetTargetValueVisitor V;
-  return V.visit(Inst);
-}
-
 static bool isGlobalOrArgAttr(StratifiedAttrs Attr) {
   return Attr.reset(AttrEscapedIndex).reset(AttrUnknownIndex).any();
 }
@@ -851,7 +768,6 @@ CFLAAResult::FunctionInfo CFLAAResult::buildSetsFrom(Function *Fn) {
 
   auto &Graph = GraphBuilder.getCFLGraph();
   SmallVector<Value *, 16> Worklist;
-  SmallPtrSet<Value *, 16> Globals;
   for (auto Node : Graph.nodes())
     Worklist.push_back(Node);
 
@@ -861,17 +777,12 @@ CFLAAResult::FunctionInfo CFLAAResult::buildSetsFrom(Function *Fn) {
     if (canSkipAddingToSets(CurValue))
       continue;
 
-    if (isa<GlobalValue>(CurValue))
-      Globals.insert(CurValue);
-
     for (const auto &Edge : Graph.edgesFor(CurValue)) {
       auto Label = Edge.Type;
       auto *OtherValue = Edge.Other;
 
       if (canSkipAddingToSets(OtherValue))
         continue;
-      if (isa<GlobalValue>(OtherValue))
-        Globals.insert(OtherValue);
 
       bool Added;
       switch (directionOfEdgeType(Label)) {
@@ -896,20 +807,20 @@ CFLAAResult::FunctionInfo CFLAAResult::buildSetsFrom(Function *Fn) {
   }
 
   // Special handling for globals and arguments
-  auto ProcessGlobalOrArgValue = [&SetBuilder](Value &Val) {
-    SetBuilder.add(&Val);
-    auto Attr = valueToAttr(&Val);
+  for (auto *External : GraphBuilder.getExternalValues()) {
+    SetBuilder.add(External);
+    auto Attr = valueToAttr(External);
     if (Attr.hasValue()) {
-      SetBuilder.noteAttributes(&Val, *Attr);
-      // TODO: do we need to filter out non-pointer values here?
-      SetBuilder.addAttributesBelow(&Val, AttrUnknown);
+      SetBuilder.noteAttributes(External, *Attr);
+      SetBuilder.addAttributesBelow(External, AttrUnknown);
     }
-  };
+  }
 
-  for (auto &Arg : Fn->args())
-    ProcessGlobalOrArgValue(Arg);
-  for (auto *Global : Globals)
-    ProcessGlobalOrArgValue(*Global);
+  for (auto *Escape : GraphBuilder.getEscapedValues()) {
+    SetBuilder.add(Escape);
+    SetBuilder.noteAttributes(Escape, AttrEscaped);
+    SetBuilder.addAttributesBelow(Escape, AttrUnknown);
+  }
 
   return FunctionInfo(SetBuilder.build(), GraphBuilder.takeReturnValues());
 }
index 0e20343af1e1236d4b8cbdfe850b206e4a5ff09a..d0de13910a7346a33eb56dcaec6c9170bebb6aec 100644 (file)
@@ -621,4 +621,4 @@ private:
   bool inbounds(StratifiedIndex N) const { return N < Links.size(); }
 };
 }
-#endif // LLVM_ADT_STRATIFIEDSETS_H
+#endif // LLVM_ADT_STRATIFIEDSETS_H
\ No newline at end of file
index a7ab3e83829081d007100827c9ad4b92a0a34bdd..068085e73d437617d434220252fefe5fa6c05a78 100644 (file)
@@ -30,3 +30,65 @@ define void @test_global_param(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
+}
index 6121dca1345ddcfbd3edeeae12daf6fa9ea2f4a6..083b5ef3d8283ae005540f8b36b0571cf0eb45e1 100644 (file)
@@ -2,10 +2,10 @@
 ; its own stratified set. This would make cases like the one in @test say that
 ; nothing (except %Escapes and %Arg) can alias
 
-; RUN: opt < %s -disable-basicaa -cfl-aa -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
 
 ; CHECK:     Function: test
-; CHECK:     MayAlias: i8* %Arg, i8* %Escapes
+; CHECK:     NoAlias: i8* %Arg, i8* %Escapes
 ; CHECK:     MayAlias: i8* %Arg, i8* %Retrieved
 ; CHECK:     MayAlias: i8* %Escapes, i8* %Retrieved
 define void @test(i8* %Arg) {
index a432cea8a1dfb79a364ff49a0828764dabaf45f7..61ed5ea381638333167f1a9d63223aabc24b0eac 100644 (file)
@@ -1,16 +1,19 @@
-; RUN: opt < %s -disable-basicaa -cfl-aa -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
 
 ; CHECK-LABEL: Function: test1
-; CHECK: 0 no alias responses
+; CHECK: MayAlias: i32* %X, i32* %tmp
+; CHECK: MayAlias: i32* %tmp, i8** %ap
+; CHECK: NoAlias: i8** %ap, i8** %aq
+; CHECK: MayAlias: i32* %tmp, i8** %aq
 
-define i32 @test1(i32 %X, ...) {
+define i32* @test1(i32* %X, ...) {
   ; Initialize variable argument processing
   %ap = alloca i8*
   %ap2 = bitcast i8** %ap to i8*
   call void @llvm.va_start(i8* %ap2)
 
-  ; Read a single integer argument
-  %tmp = va_arg i8** %ap, i32
+  ; Read a single pointer argument
+  %tmp = va_arg i8** %ap, i32*
 
   ; Demonstrate usage of llvm.va_copy and llvm.va_end
   %aq = alloca i8*
@@ -20,7 +23,7 @@ define i32 @test1(i32 %X, ...) {
 
   ; Stop processing of arguments.
   call void @llvm.va_end(i8* %ap2)
-  ret i32 %tmp
+  ret i32* %tmp
 }
 
 declare void @llvm.va_start(i8*)