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