[llvm-commits] [poolalloc] r98781 - in /poolalloc/trunk: include/dsa/DSCallGraph.h include/dsa/DataStructure.h include/dsa/svset.h lib/DSA/BottomUpClosure.cpp lib/DSA/CompleteBottomUp.cpp lib/DSA/DataStructure.cpp lib/DSA/Local.cpp

Andrew Lenharth andrewl at lenharth.org
Wed Mar 17 17:03:53 PDT 2010


Author: alenhar2
Date: Wed Mar 17 19:03:53 2010
New Revision: 98781

URL: http://llvm.org/viewvc/llvm-project?rev=98781&view=rev
Log:
Use generic EquivalenceClass to store SCCs and clean up the mess that was DSSCCGraph

Modified:
    poolalloc/trunk/include/dsa/DSCallGraph.h
    poolalloc/trunk/include/dsa/DataStructure.h
    poolalloc/trunk/include/dsa/svset.h
    poolalloc/trunk/lib/DSA/BottomUpClosure.cpp
    poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp
    poolalloc/trunk/lib/DSA/DataStructure.cpp
    poolalloc/trunk/lib/DSA/Local.cpp

Modified: poolalloc/trunk/include/dsa/DSCallGraph.h
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DSCallGraph.h?rev=98781&r1=98780&r2=98781&view=diff
==============================================================================
--- poolalloc/trunk/include/dsa/DSCallGraph.h (original)
+++ poolalloc/trunk/include/dsa/DSCallGraph.h Wed Mar 17 19:03:53 2010
@@ -18,10 +18,10 @@
 #include "dsa/keyiterator.h"
 #include <map>
 
-#include "llvm/Function.h"
-#include "llvm/DerivedTypes.h"
+//Fix in 2.8, EQC includes cassert
+#include <cassert>
+#include "llvm/ADT/EquivalenceClasses.h"
 #include "llvm/Support/CallSite.h"
-#include "llvm/Support/FormattedStream.h"
 
 
 class DSCallGraph {
@@ -31,31 +31,44 @@
   typedef std::map<const llvm::Function*, FuncSet> SimpleCalleesTy;
 
 private:
+  //ActualCallees contains CallSite -> Function mappings
   ActualCalleesTy ActualCallees;
+  //SimpleCallees contains Function -> Function mappings
   SimpleCalleesTy SimpleCallees;
 
+  //These are used for returning empty sets when the caller has no callees
   FuncSet EmptyActual;
   FuncSet EmptySimple;
 
+  //An equivalence class is exactly an SCC
+  llvm::EquivalenceClasses<const llvm::Function*> SCCs;
+
+  //Functions we know about that aren't called
+  svset<const llvm::Function*> knownRoots;
+
+  //Types for SCC construction
+  typedef std::map<const llvm::Function*, unsigned> TFMap;
+  typedef std::vector<const llvm::Function*> TFStack;
+
+  // Tarjan's SCC algorithm
+  unsigned tarjan_rec(const llvm::Function* F, TFStack& Stack, unsigned &NextID,
+                      TFMap& ValMap);
+
+  void removeECFunctions();
+
 public:
 
   DSCallGraph() {}
 
   typedef ActualCalleesTy::mapped_type::const_iterator callee_iterator;
-  typedef KeyIterator<ActualCalleesTy::const_iterator> key_iterator;
+  typedef KeyIterator<ActualCalleesTy::const_iterator> callee_key_iterator;
   typedef SimpleCalleesTy::mapped_type::const_iterator flat_iterator;
   typedef KeyIterator<SimpleCalleesTy::const_iterator> flat_key_iterator;
+  typedef FuncSet::const_iterator                      root_iterator;
+  typedef llvm::EquivalenceClasses<const llvm::Function*>::member_iterator scc_iterator;
 
-  void insert(llvm::CallSite CS, const llvm::Function* F) {
-    if (F) {
-      ActualCallees[CS].insert(F);
-      SimpleCallees[CS.getInstruction()->getParent()->getParent()].insert(F);
-      //Create an empty set for the callee, hence all called functions get to be
-      // in the call graph also.  This simplifies SCC formation
-      SimpleCallees[F];
-    }
-  }
-
+  void insert(llvm::CallSite CS, const llvm::Function* F);
+  
   template<class Iterator>
   void insert(llvm::CallSite CS, Iterator _begin, Iterator _end) {
     for (; _begin != _end; ++_begin)
@@ -76,12 +89,12 @@
     return ii->second.end();
   }
 
-  key_iterator key_begin() const {
-    return key_iterator(ActualCallees.begin());
+  callee_key_iterator key_begin() const {
+    return callee_key_iterator(ActualCallees.begin());
   }
 
-  key_iterator key_end() const {
-    return key_iterator(ActualCallees.end());
+  callee_key_iterator key_end() const {
+    return callee_key_iterator(ActualCallees.end());
   }
 
   flat_iterator flat_callee_begin(const llvm::Function* F) const {
@@ -106,6 +119,24 @@
     return flat_key_iterator(SimpleCallees.end());
   }
 
+  root_iterator root_begin() const {
+    return knownRoots.begin();
+  }
+
+  root_iterator root_end() const {
+    return knownRoots.end();
+  }
+
+  scc_iterator scc_begin(const llvm::Function* F) const {
+    assert(F == SCCs.getLeaderValue(F) && "Requested non-leader");
+    return SCCs.member_begin(SCCs.findValue(F));
+  }
+
+  scc_iterator scc_end(const llvm::Function* F) const {
+    assert(F == SCCs.getLeaderValue(F) && "Requested non-leader");
+    return SCCs.member_end();
+  }
+
 
   unsigned callee_size(llvm::CallSite CS) const {
     ActualCalleesTy::const_iterator ii = ActualCallees.find(CS);
@@ -122,196 +153,19 @@
     return sum;
   }
 
-  void clear() {
-    ActualCallees.clear();
-  }
-
-};
-
-class DSSCCGraph {
-public:
-  //SCCs, each element is an SCC
-  std::map<unsigned, DSCallGraph::FuncSet> SCCs;
-  //mapping of functions in SCCs to SCCs index
-  std::map<const llvm::Function*, unsigned> invmap;
-
-  unsigned nextSCC;
+  void buildSCCs();
 
-  //Functions we know about that aren't called
-  svset<unsigned> knownRoots;
-
-  std::map<unsigned, svset<unsigned> > SCCCallees;
-  std::map<unsigned, svset<unsigned> > ExtCallees;
-
-  DSCallGraph oldGraph;
-
-private:
-  typedef std::map<const llvm::Function*, unsigned> TFMap;
-  typedef std::vector<const llvm::Function*> TFStack;
+  void buildRoots();
 
-  bool hasPointers(const llvm::Function* F) {
-    if (F->isVarArg()) return true;
-    if (F->getReturnType()->isPointerTy()) return true;
-    for (llvm::Function::const_arg_iterator ii = F->arg_begin(), ee = F->arg_end();
-            ii != ee; ++ii)
-      if (ii->getType()->isPointerTy()) return true;
-    return false;
-  }
+  void dump();
 
-  unsigned tarjan_rec(const llvm::Function* F, TFStack& Stack, unsigned &NextID,
-                      TFMap& ValMap, DSCallGraph& cg) {
-    assert(!ValMap.count(F) && "Shouldn't revisit functions!");
-    unsigned Min = NextID++, MyID = Min;
-    ValMap[F] = Min;
-    Stack.push_back(F);
-
-    // The edges out of the current node are the call site targets...
-    for (DSCallGraph::flat_iterator ii = cg.flat_callee_begin(F),
-            ee = cg.flat_callee_end(F); ii != ee; ++ii) {
-      if (hasPointers(*ii) && !(*ii)->isDeclaration()) {
-        unsigned M = Min;
-        // Have we visited the destination function yet?
-        TFMap::iterator It = ValMap.find(*ii);
-        if (It == ValMap.end()) // No, visit it now.
-          M = tarjan_rec(*ii, Stack, NextID, ValMap, cg);
-        else if (std::find(Stack.begin(), Stack.end(), *ii) != Stack.end())
-          M = It->second;
-        if (M < Min) Min = M;
-      }
-    }
-
-    assert(ValMap[F] == MyID && "SCC construction assumption wrong!");
-    if (Min != MyID)
-      return Min; // This is part of a larger SCC!
-
-    // If this is a new SCC, process it now.
-    ++nextSCC;
-
-    const llvm::Function* NF = 0;
-    do {
-      NF = Stack.back();
-      Stack.pop_back();
-      assert(NF && "Null Function");
-      assert(invmap.find(NF) == invmap.end() && "Function already in invmap");
-      invmap[NF] = nextSCC;
-      assert(SCCs[nextSCC].find(NF) == SCCs[nextSCC].end() &&
-             "Function already in SCC");
-      SCCs[nextSCC].insert(NF);
-    } while (NF != F);
-
-    return MyID;
-  }
-
-  void buildSCC(DSCallGraph& DSG) {
-    TFStack Stack;
-    TFMap ValMap;
-    unsigned NextID = 1;
-
-    for (DSCallGraph::flat_key_iterator ii = DSG.flat_key_begin(),
-            ee = DSG.flat_key_end(); ii != ee; ++ii)
-      if (!ValMap.count(*ii))
-        tarjan_rec(*ii, Stack, NextID, ValMap, DSG);
-  }
-
-  void buildCallGraph(DSCallGraph& DSG) {
-    for(DSCallGraph::flat_key_iterator ii = DSG.flat_key_begin(),
-            ee = DSG.flat_key_end(); ii != ee; ++ii) {
-      assert (*ii && "Null Function");
-      assert(invmap.find(*ii) != invmap.end() && "Unknown Function");
-      for (DSCallGraph::flat_iterator fi = DSG.flat_callee_begin(*ii),
-              fe = DSG.flat_callee_end(*ii); fi != fe; ++fi) {
-        assert(*fi && "Null Function");
-        assert(invmap.find(*fi) != invmap.end() && "Unknown Function");
-        if (invmap[*ii] != invmap[*fi]) // No self calls
-          if (hasPointers(*fi)) {
-            if ((*fi)->isDeclaration())
-              ExtCallees[invmap[*ii]].insert(invmap[*fi]);
-            else
-              SCCCallees[invmap[*ii]].insert(invmap[*fi]);
-          }
-      }
-    }
-  }
-
-  void buildRoots() {
-    svset<unsigned> knownCallees;
-    svset<unsigned> knownCallers;
-    for (std::map<unsigned, svset<unsigned> >::iterator
-      ii = SCCCallees.begin(), ee = SCCCallees.end(); ii != ee; ++ii) {
-      knownCallees.insert(ii->second.begin(), ii->second.end());
-      knownCallers.insert(ii->first);
-    }
-    for (svset<unsigned>::iterator ii = knownCallers.begin(),
-            ee = knownCallers.end(); ii != ee; ++ii)
-      if (!knownCallees.count(*ii))
-        knownRoots.insert(*ii);
-  }
-
-  void assertMapValid() {
-    for (std::map<unsigned, DSCallGraph::FuncSet>::iterator ii = SCCs.begin(),
-            ee = SCCs.end(); ii != ee; ++ii) {
-      for (DSCallGraph::FuncSet::iterator i = ii->second.begin(),
-              e = ii->second.end(); i != e; ++i) {
-        assert(*i && "Null Function in map");
-        assert(invmap.find(*i) != invmap.end() && "Function not in invmap");
-        assert(invmap[*i] == ii->first && "invmap doesn't match map");
-      }
-    }
-
-    for (std::map<const llvm::Function*, unsigned>::iterator ii = invmap.begin(),
-            ee = invmap.end(); ii != ee; ++ii) {
-      assert(ii->first && "Null Function in invmap");
-      assert(SCCs.find(ii->second) != SCCs.end() && "Function in invmap but not in map");
-      assert(SCCs[ii->second].count(ii->first) && "SCC doesn't contain function");
-    }
+  void assertSCCRoot(const llvm::Function* F) {
+    assert(F == SCCs.getLeaderValue(F) && "Not Leader?");
   }
 
-public:
-
-  DSSCCGraph(DSCallGraph& DSG) :nextSCC(0) {
-    oldGraph = DSG;
-
-    buildSCC(DSG);
-    assertMapValid();
-
-    buildCallGraph(DSG);
-
-    buildRoots();
-    
-  }
-
-  void dump() {
-    //function map
-    for (std::map<unsigned, DSCallGraph::FuncSet>::iterator ii = SCCs.begin(),
-            ee = SCCs.end(); ii != ee; ++ii) {
-      llvm::errs() << "Functions in " << ii->first << ":";
-      for (DSCallGraph::FuncSet::iterator i = ii->second.begin(),
-              e = ii->second.end(); i != e; ++i)
-        llvm::errs() << " " << *i << "(" << invmap[*i] << ")";
-      llvm::errs() << "\n";
-    }
-
-//    for (std::map<const llvm::Function*, unsigned>::iterator ii = invmap.begin(),
-//            ee = invmap.end(); ii != ee; ++ii)
-//      llvm::errs() << ii->first << " -> " << ii->second << "\n";
-
-    //SCC map
-    for (std::map<unsigned, svset<unsigned> >::iterator ii = SCCCallees.begin(),
-            ee = SCCCallees.end(); ii != ee; ++ii) {
-      llvm::errs() << "CallGraph[" << ii->first << "]";
-      for (svset<unsigned>::iterator i = ii->second.begin(),
-              e = ii->second.end(); i != e; ++i)
-        llvm::errs() << " " << *i;
-      llvm::errs() << "\n";
-    }
-
-    //Functions we know about that aren't called
-    llvm::errs() << "Roots:";
-    for (svset<unsigned>::iterator ii = knownRoots.begin(),
-            ee = knownRoots.end(); ii != ee; ++ii)
-      llvm::errs() << " " << *ii;
-    llvm::errs() << "\n";
-  }
+  //common helper, no good reason for it to be here rather than elsewhere
+  static bool hasPointers(const llvm::Function* F);
+  static bool hasPointers(llvm::CallSite& CS);
 
 };
 

Modified: poolalloc/trunk/include/dsa/DataStructure.h
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/DataStructure.h?rev=98781&r1=98780&r2=98781&view=diff
==============================================================================
--- poolalloc/trunk/include/dsa/DataStructure.h (original)
+++ poolalloc/trunk/include/dsa/DataStructure.h Wed Mar 17 19:03:53 2010
@@ -235,11 +235,12 @@
   bool runOnModuleInternal(Module &M);
 
 private:
-  void mergeSCCs(DSSCCGraph& DSG);
+  void mergeSCCs();
   
-  DSGraph* postOrder(DSSCCGraph& DSG, unsigned scc, svset<unsigned>& marked);
+  DSGraph* postOrder(const Function*,
+                     svset<const Function*>& marked);
   
-  void calculateGraph(DSGraph* G, DSSCCGraph& DSG);
+  void calculateGraph(DSGraph* G);
 
   void CloneAuxIntoGlobal(DSGraph* G);
   void cloneGlobalsInto(DSGraph* G);

Modified: poolalloc/trunk/include/dsa/svset.h
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/include/dsa/svset.h?rev=98781&r1=98780&r2=98781&view=diff
==============================================================================
--- poolalloc/trunk/include/dsa/svset.h (original)
+++ poolalloc/trunk/include/dsa/svset.h Wed Mar 17 19:03:53 2010
@@ -134,6 +134,11 @@
     return std::make_pair(i, insertion);
   }
 
+  /// Insert a value into the sorted vector.
+  iterator insert(iterator position, const value_type& x) {
+    return insert(x).first;
+  }
+
   /// Insert a range.
   template < typename Iterator >
   void insert(Iterator _begin, Iterator _end) {

Modified: poolalloc/trunk/lib/DSA/BottomUpClosure.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/BottomUpClosure.cpp?rev=98781&r1=98780&r2=98781&view=diff
==============================================================================
--- poolalloc/trunk/lib/DSA/BottomUpClosure.cpp (original)
+++ poolalloc/trunk/lib/DSA/BottomUpClosure.cpp Wed Mar 17 19:03:53 2010
@@ -55,25 +55,26 @@
 // entry-points correctly.  As a bonus, we can be more aggressive at propagating
 // information upwards, as long as we don't remove unresolved call sites.
 bool BUDataStructures::runOnModuleInternal(Module& M) {
-  //Find SCCs and make SCC call graph
-  DSSCCGraph DSG(callgraph);
+  llvm::errs() << "BU is currently being worked in in very invasive ways.\n"
+          << "It is probably broken right now\n";
 
-  errs() << "DSNode: " << sizeof(DSNode) << "\nDSCallSite: "
-          << sizeof(DSCallSite) << "\n";
+  //Find SCCs and make SCC call graph
+  callgraph.buildSCCs();
+  callgraph.buildRoots();
 
-//  DSG.dump();
+  //  callgraph.dump();
 
   //merge SCCs
-  mergeSCCs(DSG);
+  mergeSCCs();
 
   //Post order traversal:
   {
     //errs() << *DSG.knownRoots.begin() << " -> " << *DSG.knownRoots.rbegin() << "\n";
-    svset<unsigned> marked;
-    for (svset<unsigned>::const_iterator ii = DSG.knownRoots.begin(),
-         ee = DSG.knownRoots.end(); ii != ee; ++ii) {
-      //errs() << *ii << " ";
-      DSGraph* G = postOrder(DSG, *ii, marked);
+    svset<const Function*> marked;
+    for (DSCallGraph::root_iterator ii = callgraph.root_begin(),
+         ee = callgraph.root_end(); ii != ee; ++ii) {
+      errs() << (*ii)->getName() << " ";
+      DSGraph* G = postOrder(*ii, marked);
       CloneAuxIntoGlobal(G);
     }
   }
@@ -164,22 +165,23 @@
   return false;
 }
 
-void BUDataStructures::mergeSCCs(DSSCCGraph& DSG) {
+void BUDataStructures::mergeSCCs() {
 
-  for (std::map<unsigned, DSCallGraph::FuncSet>::iterator ii = DSG.SCCs.begin(),
-       ee = DSG.SCCs.end(); ii != ee; ++ii) {
+  for (DSCallGraph::flat_key_iterator ii = callgraph.flat_key_begin(),
+       ee = callgraph.flat_key_end(); ii != ee; ++ii) {
+    // Externals can be singleton SCCs
+    if ((*ii)->isDeclaration()) continue;
+    DSGraph* SCCGraph = getOrCreateGraph(*ii);
+    unsigned SCCSize = 1;
+    callgraph.assertSCCRoot(*ii);
 
-    DSGraph* SCCGraph = 0;
-    unsigned SCCSize = 0;
-    for (DSCallGraph::FuncSet::iterator Fi = ii->second.begin(),
-         Fe = ii->second.end(); Fi != Fe; ++Fi) {
+    for (DSCallGraph::scc_iterator Fi = callgraph.scc_begin(*ii),
+         Fe = callgraph.scc_end(*ii); Fi != Fe; ++Fi) {
       const Function* F = *Fi;
       if (F->isDeclaration()) continue;
+      if (F == *ii) continue;
       ++SCCSize;
       DSGraph* NFG = getOrCreateGraph(F);
-      if (!SCCGraph) {
-        SCCGraph = NFG;
-      }
       if (NFG != SCCGraph) {
         ++NumSCCMerges;
         // Update the Function -> DSG map.
@@ -195,17 +197,22 @@
   }
 }
 
-DSGraph* BUDataStructures::postOrder(DSSCCGraph& DSG, unsigned scc,
-                                     svset<unsigned>& marked) {
-  DSGraph* G = getDSGraph(**DSG.SCCs[scc].begin());
-  if (marked.count(scc)) return G;
-
-  for(svset<unsigned>::iterator ii = DSG.SCCCallees[scc].begin(),
-          ee = DSG.SCCCallees[scc].end(); ii != ee; ++ii)
-    postOrder(DSG, *ii, marked);
+DSGraph* BUDataStructures::postOrder(const Function* F,
+                                     svset<const Function*>& marked) {
+  callgraph.assertSCCRoot(F);
+  DSGraph* G = getDSGraph(*F);
+  if (marked.count(F)) return G;
+
+  for(DSCallGraph::flat_iterator ii = callgraph.flat_callee_begin(F),
+          ee = callgraph.flat_callee_end(F); ii != ee; ++ii) {
+    callgraph.assertSCCRoot(*ii);
+    assert (*ii != F && "Simple loop in callgraph");
+    if (!(*ii)->isDeclaration())
+      postOrder(*ii, marked);
+  }
 
-  marked.insert(scc);
-  calculateGraph(G, DSG);
+  marked.insert(F);
+  calculateGraph(G);
   return G;
 }
 
@@ -262,7 +269,7 @@
   }
 }
 
-void BUDataStructures::calculateGraph(DSGraph* Graph, DSSCCGraph& DSG) {
+void BUDataStructures::calculateGraph(DSGraph* Graph) {
   DEBUG(Graph->AssertGraphOK(); Graph->getGlobalsGraph()->AssertGraphOK());
 
   // If this graph contains the main function, clone the globals graph into this
@@ -281,8 +288,8 @@
    // Note that this is *required* for correctness.  If a callee contains a use
    // of a global, we have to make sure to link up nodes due to global-argument
    // bindings.
-   if (ContainsMain)
-     cloneGlobalsInto(Graph);
+//   if (ContainsMain)
+//     cloneGlobalsInto(Graph);
 
   // Move our call site list into TempFCs so that inline call sites go into the
   // new call site list and doesn't invalidate our iterators!
@@ -305,8 +312,8 @@
       continue;
     }
 
-    std::copy(DSG.oldGraph.callee_begin(CS.getCallSite()),
-              DSG.oldGraph.callee_end(CS.getCallSite()),
+    std::copy(callgraph.callee_begin(CS.getCallSite()),
+              callgraph.callee_end(CS.getCallSite()),
               std::back_inserter(CalledFuncs));
 
     std::vector<const Function*>::iterator ErasePoint =

Modified: poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp?rev=98781&r1=98780&r2=98781&view=diff
==============================================================================
--- poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp (original)
+++ poolalloc/trunk/lib/DSA/CompleteBottomUp.cpp Wed Mar 17 19:03:53 2010
@@ -49,7 +49,7 @@
   DSGraph::ScalarMapTy& SM = G->getScalarMap();
 
   //mege nodes in the global graph for these functions
-  for (DSCallGraph::key_iterator ii = callgraph.key_begin(),
+  for (DSCallGraph::callee_key_iterator ii = callgraph.key_begin(),
        ee = callgraph.key_end(); ii != ee; ++ii) {
     DSCallGraph::callee_iterator csi = callgraph.callee_begin(*ii),
             cse = callgraph.callee_end(*ii);

Modified: poolalloc/trunk/lib/DSA/DataStructure.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/DataStructure.cpp?rev=98781&r1=98780&r2=98781&view=diff
==============================================================================
--- poolalloc/trunk/lib/DSA/DataStructure.cpp (original)
+++ poolalloc/trunk/lib/DSA/DataStructure.cpp Wed Mar 17 19:03:53 2010
@@ -1268,7 +1268,8 @@
   // Empty map so next time memory is released, data structures are not
   // re-deleted.
   DSInfo.clear();
-  callgraph.clear();
+  //FIXME:
+//  callgraph.clear();
   delete GlobalsGraph;
   GlobalsGraph = 0;
 }

Modified: poolalloc/trunk/lib/DSA/Local.cpp
URL: http://llvm.org/viewvc/llvm-project/poolalloc/trunk/lib/DSA/Local.cpp?rev=98781&r1=98780&r2=98781&view=diff
==============================================================================
--- poolalloc/trunk/lib/DSA/Local.cpp (original)
+++ poolalloc/trunk/lib/DSA/Local.cpp Wed Mar 17 19:03:53 2010
@@ -749,7 +749,14 @@
   if (visitAllocation(CS))
     return;
 
+  //Can't do much about inline asm (yet!)
   if (isa<InlineAsm>(CS.getCalledValue())) return;
+
+  //uninteresting call
+  if (!DSCallGraph::hasPointers(CS))
+    return;
+  
+
 //  if (InlineAsm* IASM = dyn_cast<InlineAsm>(CS.getCalledValue())) {
 //    if (IASM->hasSideEffects())
 //      errs() << ASM w/ Side Effects\n";





More information about the llvm-commits mailing list