[llvm] r369025 - [CallGraph] Refine call graph for indirect calls with !callees metadata

Benjamin Kramer via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 16 03:58:17 PDT 2019


This crashes clang on the attached test case, I reverted the change in
r369096.

$ clang -O3 -c -fexperimental-new-pass-manager -fprofile-generate t.ii
clang: llvm/lib/Analysis/LazyCallGraph.cpp:1535: void
llvm::LazyCallGraph::removeDeadFunction(llvm::Function &): Assertion
`RC.size() == 1 && "Dead functions must be in a singular RefSCC"' failed.
Stack dump:
0. Program arguments: clang -cc1 -triple x86_64-unknown-linux-gnu -emit-obj
-disable-free -main-file-name t.ii -mrelocation-model static -mthread-model
posix -mframe-pointer=none -fmath-errno -masm-verbose -mconstructor-aliases
-munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info
-debugger-tuning=gdb -fprofile-instrument=llvm -coverage-notes-file
/tmp/reduce/t.gcno -resource-dir lib/clang/10.0.0 -O3 -fdeprecated-macro
-fdebug-compilation-dir /tmp/reduce -ferror-limit 19 -fmessage-length 0
-fexperimental-new-pass-manager -fobjc-runtime=gcc -fcxx-exceptions
-fexceptions -fdiagnostics-show-option -fcolor-diagnostics -vectorize-loops
-vectorize-slp -faddrsig -o t.o -x c++-cpp-output t.ii
1. <eof> parser at end of file
2. Optimizer

On Thu, Aug 15, 2019 at 7:46 PM Mark Lacey via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> Author: rudkx
> Date: Thu Aug 15 10:47:53 2019
> New Revision: 369025
>
> URL: http://llvm.org/viewvc/llvm-project?rev=369025&view=rev
> Log:
> [CallGraph] Refine call graph for indirect calls with !callees metadata
>
> For indirect call sites having a small set of possible callees,
> !callees metadata can be used to indicate what those callees are.
> This patch updates the call graph and lazy call graph analyses so
> that they consider this metadata when encountering call sites. For
> the call graph, it adds a new external call graph node to the graph
> for each unique !callees metadata node. A call graph edge connects
> an indirect call site with the external node associated with the
> !callees metadata that is attached to it. And there is an edge from
> this external node to each of the callees indicated by the metadata.
> Similarly, for the lazy call graph, the patch adds Ref edges from a
> caller to the possible callees indicated by the metadata.
>
> The primary purpose of the patch is to facilitate iterating over the
> functions in a module such that all of the callees indicated by a
> given !callees metadata node will be visited prior to the functions
> containing call sites annotated by that node. This property is
> required by optimizations performing a bottom-up traversal of the
> SCC DAG. For example, the inliner can be made to inline through an
> indirect call. If the call site is annotated with !callees metadata,
> this patch ensures that the inliner will have visited all of the
> callees prior to the caller, allowing it to reliably compute the
> cost of inlining one or more of the potential callees.
>
> Original patch by @mssimpso. I've made some small changes to get it
> to apply, build, and pass tests on the top of tree, as well as
> some minor tweaks to formatting and functionality.
>
> Subscribers: mehdi_amini, hiraditya, llvm-commits, mssimpso
>
> Tags: #llvm
>
> Differential Revision: https://reviews.llvm.org/D39339
>
> Added:
>     llvm/trunk/test/Analysis/CallGraph/callees-metadata.ll
>     llvm/trunk/test/Analysis/LazyCallGraph/callees-metadata.ll
> Modified:
>     llvm/trunk/include/llvm/Analysis/CallGraph.h
>     llvm/trunk/include/llvm/IR/CallSite.h
>     llvm/trunk/lib/Analysis/CGSCCPassManager.cpp
>     llvm/trunk/lib/Analysis/CallGraph.cpp
>     llvm/trunk/lib/Analysis/LazyCallGraph.cpp
>     llvm/trunk/test/Analysis/CallGraph/non-leaf-intrinsics.ll
>
> Modified: llvm/trunk/include/llvm/Analysis/CallGraph.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/CallGraph.h?rev=369025&r1=369024&r2=369025&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Analysis/CallGraph.h (original)
> +++ llvm/trunk/include/llvm/Analysis/CallGraph.h Thu Aug 15 10:47:53 2019
> @@ -46,6 +46,7 @@
>  #define LLVM_ANALYSIS_CALLGRAPH_H
>
>  #include "llvm/ADT/GraphTraits.h"
> +#include "llvm/ADT/MapVector.h"
>  #include "llvm/ADT/STLExtras.h"
>  #include "llvm/IR/Function.h"
>  #include "llvm/IR/InstrTypes.h"
> @@ -76,9 +77,22 @@ class CallGraph {
>    using FunctionMapTy =
>        std::map<const Function *, std::unique_ptr<CallGraphNode>>;
>
> +  /// \brief A type for maintaining dummy nodes.
> +  ///
> +  /// Dummy nodes (i.e., nodes having a null function) include, for
> example,
> +  /// those created to represent !callees metadata. We use a void pointer
> as
> +  /// the key to allow for various kinds of dummy nodes. We use a
> MapVector to
> +  /// ensure a deterministic iteration order (there's no good way to sort
> dummy
> +  /// nodes). A deterministic iteration order is primarily useful for
> printing.
> +  using DummyNodeMapTy =
> +      MapVector<const MDNode *, std::unique_ptr<CallGraphNode>>;
> +
>    /// A map from \c Function* to \c CallGraphNode*.
>    FunctionMapTy FunctionMap;
>
> +  /// \brief A map for maintaining dummy nodes.
> +  DummyNodeMapTy DummyNodeMap;
> +
>    /// This node has edges to all external functions and those internal
>    /// functions that have their address taken.
>    CallGraphNode *ExternalCallingNode;
> @@ -155,6 +169,9 @@ public:
>    /// Similar to operator[], but this will insert a new CallGraphNode for
>    /// \c F if one does not already exist.
>    CallGraphNode *getOrInsertFunction(const Function *F);
> +
> +  /// \brief Return the dummy node associated with the given metadata
> node.
> +  CallGraphNode *getOrInsertNodeForCalleesMD(MDNode *Callees);
>  };
>
>  /// A node in the call graph for a module.
>
> Modified: llvm/trunk/include/llvm/IR/CallSite.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/CallSite.h?rev=369025&r1=369024&r2=369025&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/CallSite.h (original)
> +++ llvm/trunk/include/llvm/IR/CallSite.h Thu Aug 15 10:47:53 2019
> @@ -663,6 +663,30 @@ public:
>      return false;
>    }
>
> +  /// Return the set of functions this call site is known to call. For
> direct
> +  /// calls, the returned set contains the called function. For indirect
> calls,
> +  /// this function collects known callees from !callees metadata, if
> present.
> +  SmallVector<FunTy *, 1> getKnownCallees() {
> +    SmallVector<FunTy *, 1> Callees;
> +
> +    if (getCalledFunction()) {
> +      // If the call site is direct, just add the called function to the
> set.
> +      Callees.push_back(getCalledFunction());
> +      return Callees;
> +    }
> +
> +    InstrTy *Inst = getInstruction();
> +    if (auto *Node = Inst->getMetadata(LLVMContext::MD_callees)) {
> +      // Otherwise, if the call site is indirect, collect the known
> callees from
> +      // !callees metadata if present.
> +      for (const MDOperand &Op : Node->operands())
> +        if (auto *MDConstant = mdconst::extract_or_null<Constant>(Op))
> +          Callees.push_back(cast<FunTy>(MDConstant));
> +    }
> +
> +    return Callees;
> +  }
> +
>  private:
>    IterTy getCallee() const {
>      return cast<CallBase>(getInstruction())->op_end() - 1;
>
> Modified: llvm/trunk/lib/Analysis/CGSCCPassManager.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CGSCCPassManager.cpp?rev=369025&r1=369024&r2=369025&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Analysis/CGSCCPassManager.cpp (original)
> +++ llvm/trunk/lib/Analysis/CGSCCPassManager.cpp Thu Aug 15 10:47:53 2019
> @@ -449,7 +449,7 @@ LazyCallGraph::SCC &llvm::updateCGAndAna
>    // irrelevant.
>    for (Instruction &I : instructions(F))
>      if (auto CS = CallSite(&I))
> -      if (Function *Callee = CS.getCalledFunction())
> +      for (Function *Callee : CS.getKnownCallees()) {
>          if (Visited.insert(Callee).second && !Callee->isDeclaration()) {
>            Node &CalleeN = *G.lookup(*Callee);
>            Edge *E = N->lookup(CalleeN);
> @@ -467,6 +467,7 @@ LazyCallGraph::SCC &llvm::updateCGAndAna
>            if (!E->isCall())
>              PromotedRefTargets.insert(&CalleeN);
>          }
> +      }
>
>    // Now walk all references.
>    for (Instruction &I : instructions(F))
>
> Modified: llvm/trunk/lib/Analysis/CallGraph.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CallGraph.cpp?rev=369025&r1=369024&r2=369025&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Analysis/CallGraph.cpp (original)
> +++ llvm/trunk/lib/Analysis/CallGraph.cpp Thu Aug 15 10:47:53 2019
> @@ -37,6 +37,7 @@ CallGraph::CallGraph(Module &M)
>
>  CallGraph::CallGraph(CallGraph &&Arg)
>      : M(Arg.M), FunctionMap(std::move(Arg.FunctionMap)),
> +      DummyNodeMap(std::move(Arg.DummyNodeMap)),
>        ExternalCallingNode(Arg.ExternalCallingNode),
>        CallsExternalNode(std::move(Arg.CallsExternalNode)) {
>    Arg.FunctionMap.clear();
> @@ -53,6 +54,8 @@ CallGraph::~CallGraph() {
>  #ifndef NDEBUG
>    for (auto &I : FunctionMap)
>      I.second->allReferencesDropped();
> +  for (auto &N : DummyNodeMap)
> +    N.second->allReferencesDropped();
>  #endif
>  }
>
> @@ -74,7 +77,14 @@ void CallGraph::addToCallGraph(Function
>      for (Instruction &I : BB) {
>        if (auto *Call = dyn_cast<CallBase>(&I)) {
>          const Function *Callee = Call->getCalledFunction();
> -        if (!Callee || !Intrinsic::isLeaf(Callee->getIntrinsicID()))
> +        MDNode *CalleesMD = I.getMetadata(LLVMContext::MD_callees);
> +        if (!Callee && CalleesMD)
> +          // If an indirect call site has !callees metadata indicating its
> +          // possible callees, we add an edge from the call site to a
> dummy
> +          // node. When we construct the dummy node, we add edges from it
> to
> +          // the functions indicated in the !callees metadata.
> +          Node->addCalledFunction(Call,
> getOrInsertNodeForCalleesMD(CalleesMD));
> +        else if (!Callee || !Intrinsic::isLeaf(Callee->getIntrinsicID()))
>            // Indirect calls of intrinsics are not allowed so no need to
> check.
>            // We can be more precise here by using TargetArg returned by
>            // Intrinsic::isLeaf.
> @@ -105,6 +115,11 @@ void CallGraph::print(raw_ostream &OS) c
>
>    for (CallGraphNode *CN : Nodes)
>      CN->print(OS);
> +
> +  // The iteration order of the DummyNodeMap is deterministic, so we
> don't need
> +  // to sort the nodes. Just print them.
> +  for (auto &Entry : DummyNodeMap)
> +    Entry.second->print(OS);
>  }
>
>  #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
> @@ -120,6 +135,12 @@ LLVM_DUMP_METHOD void CallGraph::dump()
>  Function *CallGraph::removeFunctionFromModule(CallGraphNode *CGN) {
>    assert(CGN->empty() && "Cannot remove function from call "
>           "graph if it references other functions!");
> +
> +  // If any dummy node references the node for the given function, we
> first
> +  // need to remove those edges.
> +  for (auto &Entry : DummyNodeMap)
> +    Entry.second->removeAnyCallEdgeTo(CGN);
> +
>    Function *F = CGN->getFunction(); // Get the function for the call
> graph node
>    FunctionMap.erase(F);             // Remove the call graph node from
> the map
>
> @@ -154,6 +175,21 @@ CallGraphNode *CallGraph::getOrInsertFun
>    return CGN.get();
>  }
>
> +CallGraphNode *CallGraph::getOrInsertNodeForCalleesMD(MDNode *Callees) {
> +  auto &CGN = DummyNodeMap[Callees];
> +  if (CGN)
> +    return CGN.get();
> +  CGN = llvm::make_unique<CallGraphNode>(nullptr);
> +  for (const MDOperand &Op : Callees->operands())
> +    if (auto *MDConstant = mdconst::extract_or_null<Constant>(Op)) {
> +      auto *F = cast<Function>(MDConstant);
> +
> +      assert(!F->isIntrinsic());
> +      CGN->addCalledFunction(nullptr, getOrInsertFunction(F));
> +    }
> +  return CGN.get();
> +}
> +
>
>  //===----------------------------------------------------------------------===//
>  // Implementations of the CallGraphNode class methods.
>  //
> @@ -171,7 +207,7 @@ void CallGraphNode::print(raw_ostream &O
>      if (Function *FI = I.second->getFunction())
>        OS << "function '" << FI->getName() <<"'\n";
>      else
> -      OS << "external node\n";
> +      OS << "<<null function>><<" << I.second << ">>\n";
>    }
>    OS << '\n';
>  }
>
> Modified: llvm/trunk/lib/Analysis/LazyCallGraph.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LazyCallGraph.cpp?rev=369025&r1=369024&r2=369025&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Analysis/LazyCallGraph.cpp (original)
> +++ llvm/trunk/lib/Analysis/LazyCallGraph.cpp Thu Aug 15 10:47:53 2019
> @@ -100,12 +100,14 @@ LazyCallGraph::EdgeSequence &LazyCallGra
>    for (BasicBlock &BB : *F)
>      for (Instruction &I : BB) {
>        if (auto CS = CallSite(&I))
> -        if (Function *Callee = CS.getCalledFunction())
> +        for (Function *Callee : CS.getKnownCallees())
>            if (!Callee->isDeclaration())
>              if (Callees.insert(Callee).second) {
>                Visited.insert(Callee);
> +              auto EdgeK = CS.getCalledFunction() ?
> LazyCallGraph::Edge::Call
> +                                                  :
> LazyCallGraph::Edge::Ref;
>                addEdge(Edges->Edges, Edges->EdgeIndexMap, G->get(*Callee),
> -                      LazyCallGraph::Edge::Call);
> +                      EdgeK);
>              }
>
>        for (Value *Op : I.operand_values())
>
> Added: llvm/trunk/test/Analysis/CallGraph/callees-metadata.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CallGraph/callees-metadata.ll?rev=369025&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/Analysis/CallGraph/callees-metadata.ll (added)
> +++ llvm/trunk/test/Analysis/CallGraph/callees-metadata.ll Thu Aug 15
> 10:47:53 2019
> @@ -0,0 +1,34 @@
> +; RUN: opt < %s -print-callgraph -disable-output 2>&1 | FileCheck %s
> +
> +; CHECK:      Call graph node <<null function>><<{{.+}}>> #uses=0
> +; CHECK-DAG:    CS<0x0> calls function 'main'
> +; CHECK-DAG:    CS<0x0> calls function 'add'
> +; CHECK-DAG:    CS<0x0> calls function 'sub'
> +;
> +; CHECK:      Call graph node for function: 'add'<<{{.+}}>> #uses=2
> +;
> +; CHECK:      Call graph node for function: 'main'<<{{.+}}>> #uses=1
> +; CHECK-NEXT:   CS<{{.+}}> calls <<null function>><<[[CALLEES:.+]]>>
> +;
> +; CHECK:      Call graph node for function: 'sub'<<{{.+}}>> #uses=2
> +;
> +; CHECK:      Call graph node <<null function>><<[[CALLEES]]>> #uses=1
> +; CHECK-DAG:    CS<0x0> calls function 'add'
> +; CHECK-DAG:    CS<0x0> calls function 'sub'
> +
> +define i64 @main(i64 %x, i64 %y, i64 (i64, i64)* %binop) {
> +  %tmp0 = call i64 %binop(i64 %x, i64 %y), !callees !0
> +  ret i64 %tmp0
> +}
> +
> +define i64 @add(i64 %x, i64 %y) {
> +  %tmp0 = add i64 %x, %y
> +  ret i64 %tmp0
> +}
> +
> +define i64 @sub(i64 %x, i64 %y) {
> +  %tmp0 = sub i64 %x, %y
> +  ret i64 %tmp0
> +}
> +
> +!0 = !{i64 (i64, i64)* @add, i64 (i64, i64)* @sub}
>
> Modified: llvm/trunk/test/Analysis/CallGraph/non-leaf-intrinsics.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/CallGraph/non-leaf-intrinsics.ll?rev=369025&r1=369024&r2=369025&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/Analysis/CallGraph/non-leaf-intrinsics.ll (original)
> +++ llvm/trunk/test/Analysis/CallGraph/non-leaf-intrinsics.ll Thu Aug 15
> 10:47:53 2019
> @@ -26,7 +26,7 @@ entry:
>  ; CHECK:  CS<0x0> calls function 'f'
>
>  ; CHECK: Call graph node for function: 'calls_patchpoint'
> -; CHECK-NEXT:  CS<[[addr_1:[^>]+]]> calls external node
> +; CHECK-NEXT:  CS<[[addr_1:[^>]+]]> calls <<null function>>
>
>  ; CHECK: Call graph node for function: 'calls_statepoint'
> -; CHECK-NEXT:  CS<[[addr_0:[^>]+]]> calls external node
> +; CHECK-NEXT:  CS<[[addr_0:[^>]+]]> calls <<null function>>
>
> Added: llvm/trunk/test/Analysis/LazyCallGraph/callees-metadata.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/LazyCallGraph/callees-metadata.ll?rev=369025&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/Analysis/LazyCallGraph/callees-metadata.ll (added)
> +++ llvm/trunk/test/Analysis/LazyCallGraph/callees-metadata.ll Thu Aug 15
> 10:47:53 2019
> @@ -0,0 +1,38 @@
> +; RUN: opt < %s -passes=print-lcg -disable-output 2>&1 | FileCheck %s
> +
> +; CHECK:      Edges in function: main
> +; CHECK-DAG:    ref  -> add
> +; CHECK-DAG:    ref  -> sub
> +;
> +; CHECK:      Edges in function: add
> +;
> +; CHECK:      Edges in function: sub
> +;
> +; CHECK:      RefSCC with 1 call SCCs:
> +; CHECK-NEXT:   SCC with 1 functions:
> +; CHECK-NEXT:     sub
> +;
> +; CHECK:      RefSCC with 1 call SCCs:
> +; CHECK-NEXT:   SCC with 1 functions:
> +; CHECK-NEXT:     add
> +;
> +; CHECK:      RefSCC with 1 call SCCs:
> +; CHECK-NEXT:   SCC with 1 functions:
> +; CHECK-NEXT:     main
> +
> +define i64 @main(i64 %x, i64 %y, i64 (i64, i64)* %binop) {
> +  %tmp0 = call i64 %binop(i64 %x, i64 %y), !callees !0
> +  ret i64 %tmp0
> +}
> +
> +define i64 @add(i64 %x, i64 %y) {
> +  %tmp0 = add i64 %x, %y
> +  ret i64 %tmp0
> +}
> +
> +define i64 @sub(i64 %x, i64 %y) {
> +  %tmp0 = sub i64 %x, %y
> +  ret i64 %tmp0
> +}
> +
> +!0 = !{i64 (i64, i64)* @add, i64 (i64, i64)* @sub}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20190816/e8a3d2b1/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: t.ii
Type: application/octet-stream
Size: 123 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20190816/e8a3d2b1/attachment.obj>


More information about the llvm-commits mailing list