<div dir="rtl"><div dir="ltr">Hi Lang,</div><div dir="ltr"><br></div><div dir="ltr">I get the following errors on Visual C++ 2013, 32 bit after this revision:</div><div dir="ltr"><br></div><div dir="ltr"><div dir="ltr">  C:\llvm\lib\ExecutionEngine\Orc\OrcTargetSupport.cpp(58): error C2440: 'reinterpret_cast' : cannot convert from 'uint64_t (__cdecl *)(llvm::JITCompileCallbackManagerBase<TargetT> *,llvm::TargetAddress)' to 'uintptr_t' </div><div dir="ltr"><br></div><div dir="ltr">  C:\llvm\lib\ExecutionEngine\Orc\IndirectionUtils.cpp(107): error C2280: 'std::unique_ptr<llvm::Module,std::default_delete< _Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function </div><div dir="ltr"><br></div><div>Yaron</div><div><br></div></div></div><div class="gmail_extra"><br><div class="gmail_quote"><div dir="ltr">2015-02-17 3:18 GMT+02:00 Lang Hames <span dir="ltr"><<a href="mailto:lhames@gmail.com" target="_blank">lhames@gmail.com</a>></span>:</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: lhames<br>
Date: Mon Feb 16 19:18:38 2015<br>
New Revision: 229461<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=229461&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=229461&view=rev</a><br>
Log:<br>
[Orc] Update the Orc indirection utils and refactor the CompileOnDemand layer.<br>
<br>
This patch replaces most of the Orc indirection utils API with a new class:<br>
JITCompileCallbackManager, which creates and manages JIT callbacks.<br>
Exposing this functionality directly allows the user to create callbacks that<br>
are associated with user supplied compilation actions. For example, you can<br>
create a callback to lazyily IR-gen something from an AST. (A kaleidoscope<br>
example demonstrating this will be committed shortly).<br>
<br>
This patch also refactors the CompileOnDemand layer to use the<br>
JITCompileCallbackManager API.<br>
<br>
<br>
Modified:<br>
    llvm/trunk/include/llvm/ExecutionEngine/Orc/CloneSubModule.h<br>
    llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h<br>
    llvm/trunk/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h<br>
    llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h<br>
    llvm/trunk/lib/ExecutionEngine/Orc/CloneSubModule.cpp<br>
    llvm/trunk/lib/ExecutionEngine/Orc/IndirectionUtils.cpp<br>
    llvm/trunk/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/CloneSubModule.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/CloneSubModule.h?rev=229461&r1=229460&r2=229461&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/CloneSubModule.h?rev=229461&r1=229460&r2=229461&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/CloneSubModule.h (original)<br>
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/CloneSubModule.h Mon Feb 16 19:18:38 2015<br>
@@ -15,6 +15,7 @@<br>
 #ifndef LLVM_EXECUTIONENGINE_ORC_CLONESUBMODULE_H<br>
 #define LLVM_EXECUTIONENGINE_ORC_CLONESUBMODULE_H<br>
<br>
+#include "llvm/ADT/DenseSet.h"<br>
 #include "llvm/Transforms/Utils/ValueMapper.h"<br>
 #include <functional><br>
<br>
@@ -36,9 +37,9 @@ void copyGVInitializer(GlobalVariable &N<br>
 void copyFunctionBody(Function &New, const Function &Orig,<br>
                       ValueToValueMapTy &VMap);<br>
<br>
-std::unique_ptr<Module><br>
-CloneSubModule(const Module &M, HandleGlobalVariableFtor HandleGlobalVariable,<br>
-               HandleFunctionFtor HandleFunction, bool KeepInlineAsm);<br>
+void CloneSubModule(Module &Dst, const Module &Src,<br>
+                    HandleGlobalVariableFtor HandleGlobalVariable,<br>
+                    HandleFunctionFtor HandleFunction, bool KeepInlineAsm);<br>
 }<br>
<br>
 #endif // LLVM_EXECUTIONENGINE_ORC_CLONESUBMODULE_H<br>
<br>
Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h?rev=229461&r1=229460&r2=229461&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h?rev=229461&r1=229460&r2=229461&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h (original)<br>
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h Mon Feb 16 19:18:38 2015<br>
@@ -33,7 +33,8 @@ namespace llvm {<br>
 /// It is expected that this layer will frequently be used on top of a<br>
 /// LazyEmittingLayer. The combination of the two ensures that each function is<br>
 /// compiled only when it is first called.<br>
-template <typename BaseLayerT> class CompileOnDemandLayer {<br>
+template <typename BaseLayerT, typename CompileCallbackMgrT><br>
+class CompileOnDemandLayer {<br>
 public:<br>
   /// @brief Lookup helper that provides compatibility with the classic<br>
   ///        static-compilation symbol resolution process.<br>
@@ -114,13 +115,6 @@ private:<br>
     // Logical module handles.<br>
     std::vector<typename CODScopedLookup::LMHandle> LMHandles;<br>
<br>
-    // Persistent manglers - one per TU.<br>
-    std::vector<PersistentMangler> PersistentManglers;<br>
-<br>
-    // Symbol resolution callback handlers - one per TU.<br>
-    std::vector<std::unique_ptr<JITResolveCallbackHandler>><br>
-        JITResolveCallbackHandlers;<br>
-<br>
     // List of vectors of module set handles:<br>
     // One vector per logical module - each vector holds the handles for the<br>
     // exploded modules for that logical module in the base layer.<br>
@@ -143,91 +137,37 @@ public:<br>
   /// @brief Handle to a set of loaded modules.<br>
   typedef typename ModuleSetInfoListT::iterator ModuleSetHandleT;<br>
<br>
-  /// @brief Convenience typedef for callback inserter.<br>
-  typedef std::function<void(Module&, JITResolveCallbackHandler&)><br>
-    InsertCallbackAsmFtor;<br>
+  // @brief Fallback lookup functor.<br>
+  typedef std::function<uint64_t(const std::string &)> LookupFtor;<br>
<br>
   /// @brief Construct a compile-on-demand layer instance.<br>
-  CompileOnDemandLayer(BaseLayerT &BaseLayer,<br>
-                       InsertCallbackAsmFtor InsertCallbackAsm)<br>
-    : BaseLayer(BaseLayer), InsertCallbackAsm(InsertCallbackAsm) {}<br>
+  CompileOnDemandLayer(BaseLayerT &BaseLayer, LLVMContext &Context)<br>
+    : BaseLayer(BaseLayer),<br>
+      CompileCallbackMgr(BaseLayer, Context, 0, 64) {}<br>
<br>
   /// @brief Add a module to the compile-on-demand layer.<br>
   template <typename ModuleSetT><br>
   ModuleSetHandleT addModuleSet(ModuleSetT Ms,<br>
-                                std::unique_ptr<RTDyldMemoryManager> MM) {<br>
+                                LookupFtor FallbackLookup = nullptr) {<br>
<br>
-    const char *JITAddrSuffix = "$orc_addr";<br>
-    const char *JITImplSuffix = "$orc_impl";<br>
-<br>
-    // Create a symbol lookup context and ModuleSetInfo for this module set.<br>
+    // If the user didn't supply a fallback lookup then just use<br>
+    // getSymbolAddress.<br>
+    if (!FallbackLookup)<br>
+      FallbackLookup = [=](const std::string &Name) {<br>
+                         return findSymbol(Name, true).getAddress();<br>
+                       };<br>
+<br>
+    // Create a lookup context and ModuleSetInfo for this module set.<br>
+    // For the purposes of symbol resolution the set Ms will be treated as if<br>
+    // the modules it contained had been linked together as a dylib.<br>
     auto DylibLookup = std::make_shared<CODScopedLookup>(BaseLayer);<br>
     ModuleSetHandleT H =<br>
         ModuleSetInfos.insert(ModuleSetInfos.end(), ModuleSetInfo(DylibLookup));<br>
     ModuleSetInfo &MSI = ModuleSetInfos.back();<br>
<br>
-    // Process each of the modules in this module set. All modules share the<br>
-    // same lookup context, but each will get its own TU lookup context.<br>
-    for (auto &M : Ms) {<br>
-<br>
-      // Create a TU lookup context for this module.<br>
-      auto LMH = DylibLookup->createLogicalModule();<br>
-      MSI.LMHandles.push_back(LMH);<br>
-<br>
-      // Create a persistent mangler for this module.<br>
-      MSI.PersistentManglers.emplace_back(*M->getDataLayout());<br>
-<br>
-      // Make all calls to functions defined in this module indirect.<br>
-      JITIndirections Indirections =<br>
-          makeCallsDoubleIndirect(*M, [](const Function &) { return true; },<br>
-                                  JITImplSuffix, JITAddrSuffix);<br>
-<br>
-      // Then carve up the module into a bunch of single-function modules.<br>
-      std::vector<std::unique_ptr<Module>> ExplodedModules =<br>
-          explode(*M, Indirections);<br>
-<br>
-      // Add a resolve-callback handler for this module to look up symbol<br>
-      // addresses when requested via a callback.<br>
-      MSI.JITResolveCallbackHandlers.push_back(<br>
-          createCallbackHandlerFromJITIndirections(<br>
-              Indirections, MSI.PersistentManglers.back(),<br>
-              [=](StringRef S) {<br>
-                return DylibLookup->findSymbol(LMH, S).getAddress();<br>
-              }));<br>
-<br>
-      // Insert callback asm code into the first module.<br>
-      InsertCallbackAsm(*ExplodedModules[0],<br>
-                        *MSI.JITResolveCallbackHandlers.back());<br>
-<br>
-      // Now we need to take each of the extracted Modules and add them to<br>
-      // base layer. Each Module will be added individually to make sure they<br>
-      // can be compiled separately, and each will get its own lookaside<br>
-      // memory manager with lookup functors that resolve symbols in sibling<br>
-      // modules first.OA<br>
-      for (auto &M : ExplodedModules) {<br>
-        std::vector<std::unique_ptr<Module>> MSet;<br>
-        MSet.push_back(std::move(M));<br>
-<br>
-        BaseLayerModuleSetHandleT H = BaseLayer.addModuleSet(<br>
-            std::move(MSet),<br>
-            createLookasideRTDyldMM<SectionMemoryManager>(<br>
-                [=](const std::string &Name) {<br>
-                  if (auto Symbol = DylibLookup->findSymbol(LMH, Name))<br>
-                    return Symbol.getAddress();<br>
-                  return findSymbol(Name, true).getAddress();<br>
-                },<br>
-                [=](const std::string &Name) {<br>
-                  return DylibLookup->findSymbol(LMH, Name).getAddress();<br>
-                }));<br>
-        DylibLookup->addToLogicalModule(LMH, H);<br>
-        MSI.BaseLayerModuleSetHandles.push_back(H);<br>
-      }<br>
-<br>
-      initializeFuncAddrs(*MSI.JITResolveCallbackHandlers.back(), Indirections,<br>
-                          MSI.PersistentManglers.back(), [=](StringRef S) {<br>
-                            return DylibLookup->findSymbol(LMH, S).getAddress();<br>
-                          });<br>
-    }<br>
+    // Process each of the modules in this module set.<br>
+    for (auto &M : Ms)<br>
+      partitionAndAdd(*M, MSI, FallbackLookup);<br>
<br>
     return H;<br>
   }<br>
@@ -262,8 +202,149 @@ public:<br>
   }<br>
<br>
 private:<br>
+<br>
+  void partitionAndAdd(Module &M, ModuleSetInfo &MSI,<br>
+                       LookupFtor FallbackLookup) {<br>
+    const char *AddrSuffix = "$orc_addr";<br>
+    const char *BodySuffix = "$orc_body";<br>
+<br>
+    // We're going to break M up into a bunch of sub-modules, but we want<br>
+    // internal linkage symbols to still resolve sensibly. CODScopedLookup<br>
+    // provides the "logical module" concept to make this work, so create a<br>
+    // new logical module for M.<br>
+    auto DylibLookup = MSI.Lookup;<br>
+    auto LogicalModule = DylibLookup->createLogicalModule();<br>
+    MSI.LMHandles.push_back(LogicalModule);<br>
+<br>
+    // Partition M into a "globals and stubs" module, a "common symbols" module,<br>
+    // and a list of single-function modules.<br>
+    auto PartitionedModule = fullyPartition(M);<br>
+    auto StubsModule = std::move(PartitionedModule.GlobalVars);<br>
+    auto CommonsModule = std::move(PartitionedModule.Commons);<br>
+    auto FunctionModules = std::move(PartitionedModule.Functions);<br>
+<br>
+    // Emit the commons stright away.<br>
+    auto CommonHandle = addModule(std::move(CommonsModule), MSI, LogicalModule,<br>
+                                  FallbackLookup);<br>
+    BaseLayer.emitAndFinalize(CommonHandle);<br>
+<br>
+    // Map of definition names to callback-info data structures. We'll use<br>
+    // this to build the compile actions for the stubs below.<br>
+    typedef std::map<std::string,<br>
+                     typename CompileCallbackMgrT::CompileCallbackInfo><br>
+      StubInfoMap;<br>
+    StubInfoMap StubInfos;<br>
+<br>
+    // Now we need to take each of the extracted Modules and add them to<br>
+    // base layer. Each Module will be added individually to make sure they<br>
+    // can be compiled separately, and each will get its own lookaside<br>
+    // memory manager that will resolve within this logical module first.<br>
+    for (auto &SubM : FunctionModules) {<br>
+<br>
+      // Keep track of the stubs we create for this module so that we can set<br>
+      // their compile actions.<br>
+      std::vector<typename StubInfoMap::iterator> NewStubInfos;<br>
+<br>
+      // Search for function definitions and insert stubs into the stubs<br>
+      // module.<br>
+      for (auto &F : *SubM) {<br>
+        if (F.isDeclaration())<br>
+          continue;<br>
+<br>
+        std::string Name = F.getName();<br>
+        Function *Proto = StubsModule->getFunction(Name);<br>
+        assert(Proto && "Failed to clone function decl into stubs module.");<br>
+        auto CallbackInfo =<br>
+          CompileCallbackMgr.getCompileCallback(*Proto->getFunctionType());<br>
+        GlobalVariable *FunctionBodyPointer =<br>
+          createImplPointer(*Proto, Name + AddrSuffix,<br>
+                            CallbackInfo.getAddress());<br>
+        makeStub(*Proto, *FunctionBodyPointer);<br>
+<br>
+        F.setName(Name + BodySuffix);<br>
+        F.setVisibility(GlobalValue::HiddenVisibility);<br>
+<br>
+        auto KV = std::make_pair(std::move(Name), std::move(CallbackInfo));<br>
+        NewStubInfos.push_back(StubInfos.insert(StubInfos.begin(), KV));<br>
+      }<br>
+<br>
+      auto H = addModule(std::move(SubM), MSI, LogicalModule, FallbackLookup);<br>
+<br>
+      // Set the compile actions for this module:<br>
+      for (auto &KVPair : NewStubInfos) {<br>
+        std::string BodyName = Mangle(KVPair->first + BodySuffix,<br>
+                                      *M.getDataLayout());<br>
+        auto &CCInfo = KVPair->second;<br>
+        CCInfo.setCompileAction(<br>
+          [=](){<br>
+            return BaseLayer.findSymbolIn(H, BodyName, false).getAddress();<br>
+          });<br>
+      }<br>
+<br>
+    }<br>
+<br>
+    // Ok - we've processed all the partitioned modules. Now add the<br>
+    // stubs/globals module and set the update actions.<br>
+    auto StubsH =<br>
+      addModule(std::move(StubsModule), MSI, LogicalModule, FallbackLookup);<br>
+<br>
+    for (auto &KVPair : StubInfos) {<br>
+      std::string AddrName = Mangle(KVPair.first + AddrSuffix,<br>
+                                    *M.getDataLayout());<br>
+      auto &CCInfo = KVPair.second;<br>
+      CCInfo.setUpdateAction(<br>
+        CompileCallbackMgr.getLocalFPUpdater(StubsH, AddrName));<br>
+    }<br>
+  }<br>
+<br>
+  // Add the given Module to the base layer using a memory manager that will<br>
+  // perform the appropriate scoped lookup (i.e. will look first with in the<br>
+  // module from which it was extracted, then into the set to which that module<br>
+  // belonged, and finally externally).<br>
+  BaseLayerModuleSetHandleT addModule(<br>
+                               std::unique_ptr<Module> M,<br>
+                               ModuleSetInfo &MSI,<br>
+                               typename CODScopedLookup::LMHandle LogicalModule,<br>
+                               LookupFtor FallbackLookup) {<br>
+<br>
+    // Add this module to the JIT with a memory manager that uses the<br>
+    // DylibLookup to resolve symbols.<br>
+    std::vector<std::unique_ptr<Module>> MSet;<br>
+    MSet.push_back(std::move(M));<br>
+<br>
+    auto DylibLookup = MSI.Lookup;<br>
+    auto MM =<br>
+      createLookasideRTDyldMM<SectionMemoryManager>(<br>
+        [=](const std::string &Name) {<br>
+          if (auto Symbol = DylibLookup->findSymbol(LogicalModule, Name))<br>
+            return Symbol.getAddress();<br>
+          return FallbackLookup(Name);<br>
+        },<br>
+        [=](const std::string &Name) {<br>
+          return DylibLookup->findSymbol(LogicalModule, Name).getAddress();<br>
+        });<br>
+<br>
+    BaseLayerModuleSetHandleT H =<br>
+      BaseLayer.addModuleSet(std::move(MSet), std::move(MM));<br>
+    // Add this module to the logical module lookup.<br>
+    DylibLookup->addToLogicalModule(LogicalModule, H);<br>
+    MSI.BaseLayerModuleSetHandles.push_back(H);<br>
+<br>
+    return H;<br>
+  }<br>
+<br>
+  static std::string Mangle(StringRef Name, const DataLayout &DL) {<br>
+    Mangler M(&DL);<br>
+    std::string MangledName;<br>
+    {<br>
+      raw_string_ostream MangledNameStream(MangledName);<br>
+      M.getNameWithPrefix(MangledNameStream, Name);<br>
+    }<br>
+    return MangledName;<br>
+  }<br>
+<br>
   BaseLayerT &BaseLayer;<br>
-  InsertCallbackAsmFtor InsertCallbackAsm;<br>
+  CompileCallbackMgrT CompileCallbackMgr;<br>
   ModuleSetInfoListT ModuleSetInfos;<br>
 };<br>
 }<br>
<br>
Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h?rev=229461&r1=229460&r2=229461&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h?rev=229461&r1=229460&r2=229461&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h (original)<br>
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h Mon Feb 16 19:18:38 2015<br>
@@ -15,271 +15,224 @@<br>
 #define LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H<br>
<br>
 #include "JITSymbol.h"<br>
+#include "llvm/ADT/DenseSet.h"<br>
+#include "llvm/IR/IRBuilder.h"<br>
 #include "llvm/IR/Mangler.h"<br>
 #include "llvm/IR/Module.h"<br>
 #include <sstream><br>
<br>
 namespace llvm {<br>
<br>
-/// @brief Persistent name mangling.<br>
-///<br>
-///   This class provides name mangling that can outlive a Module (and its<br>
-/// DataLayout).<br>
-class PersistentMangler {<br>
+/// @brief Base class for JITLayer independent aspects of<br>
+///        JITCompileCallbackManager.<br>
+template <typename TargetT><br>
+class JITCompileCallbackManagerBase {<br>
 public:<br>
-  PersistentMangler(DataLayout DL) : DL(std::move(DL)), M(&this->DL) {}<br>
<br>
-  std::string getMangledName(StringRef Name) const {<br>
-    std::string MangledName;<br>
-    {<br>
-      raw_string_ostream MangledNameStream(MangledName);<br>
-      M.getNameWithPrefix(MangledNameStream, Name);<br>
+  /// @brief Construct a JITCompileCallbackManagerBase.<br>
+  /// @param ErrorHandlerAddress The address of an error handler in the target<br>
+  ///                            process to be used if a compile callback fails.<br>
+  /// @param NumTrampolinesPerBlock Number of trampolines to emit if there is no<br>
+  ///                             available trampoline when getCompileCallback is<br>
+  ///                             called.<br>
+  JITCompileCallbackManagerBase(TargetAddress ErrorHandlerAddress,<br>
+                                unsigned NumTrampolinesPerBlock)<br>
+    : ErrorHandlerAddress(ErrorHandlerAddress),<br>
+      NumTrampolinesPerBlock(NumTrampolinesPerBlock) {}<br>
+<br>
+  /// @brief Execute the callback for the given trampoline id. Called by the JIT<br>
+  ///        to compile functions on demand.<br>
+  TargetAddress executeCompileCallback(TargetAddress TrampolineID) {<br>
+    typename TrampolineMapT::iterator I = ActiveTrampolines.find(TrampolineID);<br>
+    // FIXME: Also raise an error in the Orc error-handler when we finally have<br>
+    //        one.<br>
+    if (I == ActiveTrampolines.end())<br>
+      return ErrorHandlerAddress;<br>
+<br>
+    // Found a callback handler. Yank this trampoline out of the active list and<br>
+    // put it back in the available trampolines list, then try to run the<br>
+    // handler's compile and update actions.<br>
+    // Moving the trampoline ID back to the available list first means there's at<br>
+    // least one available trampoline if the compile action triggers a request for<br>
+    // a new one.<br>
+    AvailableTrampolines.push_back(I->first);<br>
+    auto CallbackHandler = std::move(I->second);<br>
+    ActiveTrampolines.erase(I);<br>
+<br>
+    if (auto Addr = CallbackHandler.Compile()) {<br>
+      CallbackHandler.Update(Addr);<br>
+      return Addr;<br>
     }<br>
-    return MangledName;<br>
+    return ErrorHandlerAddress;<br>
   }<br>
<br>
-private:<br>
-  DataLayout DL;<br>
-  Mangler M;<br>
-};<br>
+protected:<br>
<br>
-/// @brief Handle callbacks from the JIT process requesting the definitions of<br>
-///        symbols.<br>
-///<br>
-///   This utility is intended to be used to support compile-on-demand for<br>
-/// functions.<br>
-class JITResolveCallbackHandler {<br>
-private:<br>
-  typedef std::vector<std::string> FuncNameList;<br>
+  typedef std::function<TargetAddress()> CompileFtorT;<br>
+  typedef std::function<void(TargetAddress)> UpdateFtorT;<br>
<br>
-public:<br>
-  typedef FuncNameList::size_type StubIndex;<br>
+  struct CallbackHandler {<br>
+    CompileFtorT Compile;<br>
+    UpdateFtorT Update;<br>
+  };<br>
+<br>
+  TargetAddress ErrorHandlerAddress;<br>
+  unsigned NumTrampolinesPerBlock;<br>
+<br>
+  typedef std::map<TargetAddress, CallbackHandler> TrampolineMapT;<br>
+  TrampolineMapT ActiveTrampolines;<br>
+  std::vector<TargetAddress> AvailableTrampolines;<br>
+};<br>
<br>
+/// @brief Manage compile callbacks.<br>
+template <typename JITLayerT, typename TargetT><br>
+class JITCompileCallbackManager :<br>
+    public JITCompileCallbackManagerBase<TargetT> {<br>
 public:<br>
-  /// @brief Create a JITResolveCallbackHandler with the given functors for<br>
-  ///        looking up symbols and updating their use-sites.<br>
-  ///<br>
-  /// @return A JITResolveCallbackHandler instance that will invoke the<br>
-  ///         Lookup and Update functors as needed to resolve missing symbol<br>
-  ///         definitions.<br>
-  template <typename LookupFtor, typename UpdateFtor><br>
-  static std::unique_ptr<JITResolveCallbackHandler> create(LookupFtor Lookup,<br>
-                                                           UpdateFtor Update);<br>
-<br>
-  /// @brief Destroy instance. Does not modify existing emitted symbols.<br>
-  ///<br>
-  ///   Not-yet-emitted symbols will need to be resolved some other way after<br>
-  /// this class is destroyed.<br>
-  virtual ~JITResolveCallbackHandler() {}<br>
-<br>
-  /// @brief Add a function to be resolved on demand.<br>
-  void addFuncName(std::string Name) { FuncNames.push_back(std::move(Name)); }<br>
-<br>
-  /// @brief Get the name associated with the given index.<br>
-  const std::string &getFuncName(StubIndex Idx) const { return FuncNames[Idx]; }<br>
-<br>
-  /// @brief Returns the number of symbols being managed by this instance.<br>
-  StubIndex getNumFuncs() const { return FuncNames.size(); }<br>
-<br>
-  /// @brief Get the address for the symbol associated with the given index.<br>
-  ///<br>
-  ///   This is expected to be called by code in the JIT process itself, in<br>
-  /// order to resolve a function.<br>
-  virtual TargetAddress resolve(StubIndex StubIdx) = 0;<br>
<br>
-private:<br>
-  FuncNameList FuncNames;<br>
-};<br>
+  typedef typename JITCompileCallbackManagerBase<TargetT>::CompileFtorT<br>
+    CompileFtorT;<br>
+  typedef typename JITCompileCallbackManagerBase<TargetT>::UpdateFtorT<br>
+    UpdateFtorT;<br>
+<br>
+  /// @brief Construct a JITCompileCallbackManager.<br>
+  /// @param JIT JIT layer to emit callback trampolines, etc. into.<br>
+  /// @param Context LLVMContext to use for trampoline & resolve block modules.<br>
+  /// @param ErrorHandlerAddress The address of an error handler in the target<br>
+  ///                            process to be used if a compile callback fails.<br>
+  /// @param NumTrampolinesPerBlock Number of trampolines to allocate whenever<br>
+  ///                               there is no existing callback trampoline.<br>
+  ///                               (Trampolines are allocated in blocks for<br>
+  ///                               efficiency.)<br>
+  JITCompileCallbackManager(JITLayerT &JIT, LLVMContext &Context,<br>
+                            TargetAddress ErrorHandlerAddress,<br>
+                            unsigned NumTrampolinesPerBlock)<br>
+    : JITCompileCallbackManagerBase<TargetT>(ErrorHandlerAddress,<br>
+                                             NumTrampolinesPerBlock),<br>
+      JIT(JIT) {<br>
+    emitResolverBlock(Context);<br>
+  }<br>
<br>
-// Implementation class for JITResolveCallbackHandler.<br>
-template <typename LookupFtor, typename UpdateFtor><br>
-class JITResolveCallbackHandlerImpl : public JITResolveCallbackHandler {<br>
-public:<br>
-  JITResolveCallbackHandlerImpl(LookupFtor Lookup, UpdateFtor Update)<br>
-      : Lookup(std::move(Lookup)), Update(std::move(Update)) {}<br>
+  /// @brief Handle to a newly created compile callback. Can be used to get an<br>
+  ///        IR constant representing the address of the trampoline, and to set<br>
+  ///        the compile and update actions for the callback.<br>
+  class CompileCallbackInfo {<br>
+  public:<br>
+    CompileCallbackInfo(Constant *Addr, CompileFtorT &Compile,<br>
+                        UpdateFtorT &Update)<br>
+      : Addr(Addr), Compile(Compile), Update(Update) {}<br>
+<br>
+    Constant* getAddress() const { return Addr; }<br>
+    void setCompileAction(CompileFtorT Compile) {<br>
+      this->Compile = std::move(Compile);<br>
+    }<br>
+    void setUpdateAction(UpdateFtorT Update) {<br>
+      this->Update = std::move(Update);<br>
+    }<br>
+  private:<br>
+    Constant *Addr;<br>
+    CompileFtorT &Compile;<br>
+    UpdateFtorT &Update;<br>
+  };<br>
+<br>
+  /// @brief Get/create a compile callback with the given signature.<br>
+  CompileCallbackInfo getCompileCallback(FunctionType &FT) {<br>
+    TargetAddress TrampolineAddr = getAvailableTrampolineAddr(FT.getContext());<br>
+    auto &CallbackHandler =<br>
+      this->ActiveTrampolines[TrampolineAddr + TargetT::CallSize];<br>
+    Constant *AddrIntVal =<br>
+      ConstantInt::get(Type::getInt64Ty(FT.getContext()), TrampolineAddr);<br>
+    Constant *AddrPtrVal =<br>
+      ConstantExpr::getCast(Instruction::IntToPtr, AddrIntVal,<br>
+                            PointerType::get(&FT, 0));<br>
<br>
-  TargetAddress resolve(StubIndex StubIdx) override {<br>
-    const std::string &FuncName = getFuncName(StubIdx);<br>
-    TargetAddress Addr = Lookup(FuncName);<br>
-    Update(FuncName, Addr);<br>
-    return Addr;<br>
+    return CompileCallbackInfo(AddrPtrVal, CallbackHandler.Compile,<br>
+                               CallbackHandler.Update);<br>
+  }<br>
+<br>
+  /// @brief Get a functor for updating the value of a named function pointer.<br>
+  UpdateFtorT getLocalFPUpdater(typename JITLayerT::ModuleSetHandleT H,<br>
+                                std::string Name) {<br>
+    // FIXME: Move-capture Name once we can use C++14.<br>
+    return [=](TargetAddress Addr) {<br>
+      auto FPSym = JIT.findSymbolIn(H, Name, true);<br>
+      assert(FPSym && "Cannot find function pointer to update.");<br>
+      void *FPAddr = reinterpret_cast<void*>(<br>
+                       static_cast<uintptr_t>(FPSym.getAddress()));<br>
+      memcpy(FPAddr, &Addr, sizeof(uintptr_t));<br>
+    };<br>
   }<br>
<br>
 private:<br>
-  LookupFtor Lookup;<br>
-  UpdateFtor Update;<br>
-};<br>
<br>
-template <typename LookupFtor, typename UpdateFtor><br>
-std::unique_ptr<JITResolveCallbackHandler><br>
-JITResolveCallbackHandler::create(LookupFtor Lookup, UpdateFtor Update) {<br>
-  typedef JITResolveCallbackHandlerImpl<LookupFtor, UpdateFtor> Impl;<br>
-  return make_unique<Impl>(std::move(Lookup), std::move(Update));<br>
-}<br>
+  std::vector<std::unique_ptr<Module>><br>
+  SingletonSet(std::unique_ptr<Module> M) {<br>
+    std::vector<std::unique_ptr<Module>> Ms;<br>
+    Ms.push_back(std::move(M));<br>
+    return Ms;<br>
+  }<br>
<br>
-/// @brief Holds a list of the function names that were indirected, plus<br>
-///        mappings from each of these names to (a) the name of function<br>
-///        providing the implementation for that name (GetImplNames), and<br>
-///        (b) the name of the global variable holding the address of the<br>
-///        implementation.<br>
-///<br>
-///   This data structure can be used with a JITCallbackHandler to look up and<br>
-/// update function implementations when lazily compiling.<br>
-class JITIndirections {<br>
-public:<br>
-  JITIndirections(std::vector<std::string> IndirectedNames,<br>
-                  std::function<std::string(StringRef)> GetImplName,<br>
-                  std::function<std::string(StringRef)> GetAddrName)<br>
-      : IndirectedNames(std::move(IndirectedNames)),<br>
-        GetImplName(std::move(GetImplName)),<br>
-        GetAddrName(std::move(GetAddrName)) {}<br>
-<br>
-  std::vector<std::string> IndirectedNames;<br>
-  std::function<std::string(StringRef Name)> GetImplName;<br>
-  std::function<std::string(StringRef Name)> GetAddrName;<br>
+  void emitResolverBlock(LLVMContext &Context) {<br>
+    std::unique_ptr<Module> M(new Module("resolver_block_module",<br>
+                                         Context));<br>
+    TargetT::insertResolverBlock(*M, *this);<br>
+    auto H = JIT.addModuleSet(SingletonSet(std::move(M)), nullptr);<br>
+    JIT.emitAndFinalize(H);<br>
+    auto ResolverBlockSymbol =<br>
+      JIT.findSymbolIn(H, TargetT::ResolverBlockName, false);<br>
+    assert(ResolverBlockSymbol && "Failed to insert resolver block");<br>
+    ResolverBlockAddr = ResolverBlockSymbol.getAddress();<br>
+  }<br>
+<br>
+  TargetAddress getAvailableTrampolineAddr(LLVMContext &Context) {<br>
+    if (this->AvailableTrampolines.empty())<br>
+      grow(Context);<br>
+    assert(!this->AvailableTrampolines.empty() &&<br>
+           "Failed to grow available trampolines.");<br>
+    TargetAddress TrampolineAddr = this->AvailableTrampolines.back();<br>
+    this->AvailableTrampolines.pop_back();<br>
+    return TrampolineAddr;<br>
+  }<br>
+<br>
+  void grow(LLVMContext &Context) {<br>
+    assert(this->AvailableTrampolines.empty() && "Growing prematurely?");<br>
+    std::unique_ptr<Module> M(new Module("trampoline_block", Context));<br>
+    auto GetLabelName =<br>
+      TargetT::insertCompileCallbackTrampolines(*M, ResolverBlockAddr,<br>
+                                                this->NumTrampolinesPerBlock,<br>
+                                                this->ActiveTrampolines.size());<br>
+    auto H = JIT.addModuleSet(SingletonSet(std::move(M)), nullptr);<br>
+    JIT.emitAndFinalize(H);<br>
+    for (unsigned I = 0; I < this->NumTrampolinesPerBlock; ++I) {<br>
+      std::string Name = GetLabelName(I);<br>
+      auto TrampolineSymbol = JIT.findSymbolIn(H, Name, false);<br>
+      assert(TrampolineSymbol && "Failed to emit trampoline.");<br>
+      this->AvailableTrampolines.push_back(TrampolineSymbol.getAddress());<br>
+    }<br>
+  }<br>
+<br>
+  JITLayerT &JIT;<br>
+  TargetAddress ResolverBlockAddr;<br>
 };<br>
<br>
-/// @brief Indirect all calls to functions matching the predicate<br>
-///        ShouldIndirect through a global variable containing the address<br>
-///        of the implementation.<br>
-///<br>
-/// @return An indirection structure containing the functions that had their<br>
-///         call-sites re-written.<br>
-///<br>
-///   For each function 'F' that meets the ShouldIndirect predicate, and that<br>
-/// is called in this Module, add a common-linkage global variable to the<br>
-/// module that will hold the address of the implementation of that function.<br>
-/// Rewrite all call-sites of 'F' to be indirect calls (via the global).<br>
-/// This allows clients, either directly or via a JITCallbackHandler, to<br>
-/// change the address of the implementation of 'F' at runtime.<br>
-///<br>
-/// Important notes:<br>
-///<br>
-///   Single indirection does not preserve pointer equality for 'F'. If the<br>
-/// program was already calling 'F' indirectly through function pointers, or<br>
-/// if it was taking the address of 'F' for the purpose of pointer comparisons<br>
-/// or arithmetic double indirection should be used instead.<br>
-///<br>
-///   This method does *not* initialize the function implementation addresses.<br>
-/// The client must do this prior to running any call-sites that have been<br>
-/// indirected.<br>
-JITIndirections makeCallsSingleIndirect(<br>
-    llvm::Module &M,<br>
-    const std::function<bool(const Function &)> &ShouldIndirect,<br>
-    const char *JITImplSuffix, const char *JITAddrSuffix);<br>
-<br>
-/// @brief Replace the body of functions matching the predicate ShouldIndirect<br>
-///        with indirect calls to the implementation.<br>
-///<br>
-/// @return An indirections structure containing the functions that had their<br>
-///         implementations re-written.<br>
-///<br>
-///   For each function 'F' that meets the ShouldIndirect predicate, add a<br>
-/// common-linkage global variable to the module that will hold the address of<br>
-/// the implementation of that function and rewrite the implementation of 'F'<br>
-/// to call through to the implementation indirectly (via the global).<br>
-/// This allows clients, either directly or via a JITCallbackHandler, to<br>
-/// change the address of the implementation of 'F' at runtime.<br>
-///<br>
-/// Important notes:<br>
-///<br>
-///   Double indirection is slower than single indirection, but preserves<br>
-/// function pointer relation tests and correct behavior for function pointers<br>
-/// (all calls to 'F', direct or indirect) go the address stored in the global<br>
-/// variable at the time of the call.<br>
-///<br>
-///   This method does *not* initialize the function implementation addresses.<br>
-/// The client must do this prior to running any call-sites that have been<br>
-/// indirected.<br>
-JITIndirections makeCallsDoubleIndirect(<br>
-    llvm::Module &M,<br>
-    const std::function<bool(const Function &)> &ShouldIndirect,<br>
-    const char *JITImplSuffix, const char *JITAddrSuffix);<br>
-<br>
-/// @brief Given a set of indirections and a symbol lookup functor, create a<br>
-///        JITResolveCallbackHandler instance that will resolve the<br>
-///        implementations for the indirected symbols on demand.<br>
-template <typename SymbolLookupFtor><br>
-std::unique_ptr<JITResolveCallbackHandler><br>
-createCallbackHandlerFromJITIndirections(const JITIndirections &Indirs,<br>
-                                         const PersistentMangler &NM,<br>
-                                         SymbolLookupFtor Lookup) {<br>
-  auto GetImplName = Indirs.GetImplName;<br>
-  auto GetAddrName = Indirs.GetAddrName;<br>
-<br>
-  std::unique_ptr<JITResolveCallbackHandler> J =<br>
-      JITResolveCallbackHandler::create(<br>
-          [=](const std::string &S) {<br>
-            return Lookup(NM.getMangledName(GetImplName(S)));<br>
-          },<br>
-          [=](const std::string &S, TargetAddress Addr) {<br>
-            void *ImplPtr = reinterpret_cast<void *>(<br>
-                Lookup(NM.getMangledName(GetAddrName(S))));<br>
-            memcpy(ImplPtr, &Addr, sizeof(TargetAddress));<br>
-          });<br>
+GlobalVariable* createImplPointer(Function &F, const Twine &Name,<br>
+                                  Constant *Initializer);<br>
<br>
-  for (const auto &FuncName : Indirs.IndirectedNames)<br>
-    J->addFuncName(FuncName);<br>
+void makeStub(Function &F, GlobalVariable &ImplPointer);<br>
<br>
-  return J;<br>
-}<br>
+typedef std::map<Module*, DenseSet<const GlobalValue*>> ModulePartitionMap;<br>
<br>
-/// @brief Insert callback asm into module M for the symbols managed by<br>
-///        JITResolveCallbackHandler J.<br>
-void insertX86CallbackAsm(Module &M, JITResolveCallbackHandler &J);<br>
-<br>
-/// @brief Initialize global indirects to point into the callback asm.<br>
-template <typename LookupFtor><br>
-void initializeFuncAddrs(JITResolveCallbackHandler &J,<br>
-                         const JITIndirections &Indirs,<br>
-                         const PersistentMangler &NM, LookupFtor Lookup) {<br>
-  // Forward declare so that we can access this, even though it's an<br>
-  // implementation detail.<br>
-  std::string getJITResolveCallbackIndexLabel(unsigned I);<br>
-<br>
-  if (J.getNumFuncs() == 0)<br>
-    return;<br>
-<br>
-  //   Force a look up one of the global addresses for a function that has been<br>
-  // indirected. We need to do this to trigger the emission of the module<br>
-  // holding the callback asm. We can't rely on that emission happening<br>
-  // automatically when we look up the callback asm symbols, since lazy-emitting<br>
-  // layers can't see those.<br>
-  Lookup(NM.getMangledName(Indirs.GetAddrName(J.getFuncName(0))));<br>
-<br>
-  // Now update indirects to point to the JIT resolve callback asm.<br>
-  for (JITResolveCallbackHandler::StubIndex I = 0; I < J.getNumFuncs(); ++I) {<br>
-    TargetAddress ResolveCallbackIdxAddr =<br>
-        Lookup(getJITResolveCallbackIndexLabel(I));<br>
-    void *AddrPtr = reinterpret_cast<void *>(<br>
-        Lookup(NM.getMangledName(Indirs.GetAddrName(J.getFuncName(I)))));<br>
-    assert(AddrPtr && "Can't find stub addr global to initialize.");<br>
-    memcpy(AddrPtr, &ResolveCallbackIdxAddr, sizeof(TargetAddress));<br>
-  }<br>
-}<br>
+void partition(Module &M, const ModulePartitionMap &PMap);<br>
+<br>
+/// @brief Struct for trivial "complete" partitioning of a module.<br>
+struct FullyPartitionedModule {<br>
+  std::unique_ptr<Module> GlobalVars;<br>
+  std::unique_ptr<Module> Commons;<br>
+  std::vector<std::unique_ptr<Module>> Functions;<br>
+};<br>
+<br>
+FullyPartitionedModule fullyPartition(Module &M);<br>
<br>
-/// @brief Extract all functions matching the predicate ShouldExtract in to<br>
-///        their own modules. (Does not modify the original module.)<br>
-///<br>
-/// @return A set of modules, the first containing all symbols (including<br>
-///         globals and aliases) that did not pass ShouldExtract, and each<br>
-///         subsequent module containing one of the functions that did meet<br>
-///         ShouldExtract.<br>
-///<br>
-///   By adding the resulting modules separately (not as a set) to a<br>
-/// LazyEmittingLayer instance, compilation can be deferred until symbols are<br>
-/// actually needed.<br>
-std::vector<std::unique_ptr<llvm::Module>><br>
-explode(const llvm::Module &OrigMod,<br>
-        const std::function<bool(const Function &)> &ShouldExtract);<br>
-<br>
-/// @brief Given a module that has been indirectified, break each function<br>
-///        that has been indirected out into its own module. (Does not modify<br>
-///        the original module).<br>
-///<br>
-/// @returns A set of modules covering the symbols provided by OrigMod.<br>
-std::vector<std::unique_ptr<llvm::Module>><br>
-explode(const llvm::Module &OrigMod, const JITIndirections &Indirections);<br>
 }<br>
<br>
 #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H<br>
<br>
Modified: llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h?rev=229461&r1=229460&r2=229461&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h?rev=229461&r1=229460&r2=229461&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h (original)<br>
+++ llvm/trunk/include/llvm/ExecutionEngine/Orc/OrcTargetSupport.h Mon Feb 16 19:18:38 2015<br>
@@ -18,9 +18,37 @@<br>
<br>
 namespace llvm {<br>
<br>
-/// @brief Insert callback asm into module M for the symbols managed by<br>
-///        JITResolveCallbackHandler J.<br>
-void insertX86CallbackAsm(Module &M, JITResolveCallbackHandler &J);<br>
+class OrcX86_64 {<br>
+public:<br>
+  static const char *ResolverBlockName;<br>
+<br>
+  /// @brief Insert module-level inline callback asm into module M for the<br>
+  /// symbols managed by JITResolveCallbackHandler J.<br>
+  static void insertResolverBlock(<br>
+                                 Module &M,<br>
+                                 JITCompileCallbackManagerBase<OrcX86_64> &JCBM);<br>
+<br>
+  /// @brief Get a label name from the given index.<br>
+  typedef std::function<std::string(unsigned)> LabelNameFtor;<br>
+<br>
+  static const unsigned CallSize = 6;<br>
+<br>
+  /// @brief Insert the requested number of trampolines into the given module.<br>
+  /// @param M Module to insert the call block into.<br>
+  /// @param NumCalls Number of calls to create in the call block.<br>
+  /// @param StartIndex Optional argument specifying the index suffix to start<br>
+  ///                   with.<br>
+  /// @return A functor that provides the symbol name for each entry in the call<br>
+  ///         block.<br>
+  ///<br>
+  static LabelNameFtor insertCompileCallbackTrampolines(<br>
+                                                    Module &M,<br>
+                                                    TargetAddress TrampolineAddr,<br>
+                                                    unsigned NumCalls,<br>
+                                                    unsigned StartIndex = 0);<br>
+<br>
+};<br>
+<br>
 }<br>
<br>
 #endif // LLVM_EXECUTIONENGINE_ORC_ORCTARGETSUPPORT_H<br>
<br>
Modified: llvm/trunk/lib/ExecutionEngine/Orc/CloneSubModule.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/CloneSubModule.cpp?rev=229461&r1=229460&r2=229461&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/CloneSubModule.cpp?rev=229461&r1=229460&r2=229461&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/ExecutionEngine/Orc/CloneSubModule.cpp (original)<br>
+++ llvm/trunk/lib/ExecutionEngine/Orc/CloneSubModule.cpp Mon Feb 16 19:18:38 2015<br>
@@ -27,27 +27,20 @@ void llvm::copyFunctionBody(Function &Ne<br>
   }<br>
 }<br>
<br>
-std::unique_ptr<Module><br>
-llvm::CloneSubModule(const Module &M,<br>
+void llvm::CloneSubModule(llvm::Module &Dst, const Module &Src,<br>
                      HandleGlobalVariableFtor HandleGlobalVariable,<br>
-                     HandleFunctionFtor HandleFunction, bool KeepInlineAsm) {<br>
+                     HandleFunctionFtor HandleFunction, bool CloneInlineAsm) {<br>
<br>
   ValueToValueMapTy VMap;<br>
<br>
-  // First off, we need to create the new module.<br>
-  std::unique_ptr<Module> New =<br>
-      llvm::make_unique<Module>(M.getModuleIdentifier(), M.getContext());<br>
-<br>
-  New->setDataLayout(M.getDataLayout());<br>
-  New->setTargetTriple(M.getTargetTriple());<br>
-  if (KeepInlineAsm)<br>
-    New->setModuleInlineAsm(M.getModuleInlineAsm());<br>
+  if (CloneInlineAsm)<br>
+    Dst.appendModuleInlineAsm(Src.getModuleInlineAsm());<br>
<br>
   // Copy global variables (but not initializers, yet).<br>
-  for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();<br>
+  for (Module::const_global_iterator I = Src.global_begin(), E = Src.global_end();<br>
        I != E; ++I) {<br>
     GlobalVariable *GV = new GlobalVariable(<br>
-        *New, I->getType()->getElementType(), I->isConstant(), I->getLinkage(),<br>
+        Dst, I->getType()->getElementType(), I->isConstant(), I->getLinkage(),<br>
         (Constant *)nullptr, I->getName(), (GlobalVariable *)nullptr,<br>
         I->getThreadLocalMode(), I->getType()->getAddressSpace());<br>
     GV->copyAttributesFrom(I);<br>
@@ -55,21 +48,21 @@ llvm::CloneSubModule(const Module &M,<br>
   }<br>
<br>
   // Loop over the functions in the module, making external functions as before<br>
-  for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) {<br>
+  for (Module::const_iterator I = Src.begin(), E = Src.end(); I != E; ++I) {<br>
     Function *NF =<br>
         Function::Create(cast<FunctionType>(I->getType()->getElementType()),<br>
-                         I->getLinkage(), I->getName(), &*New);<br>
+                         I->getLinkage(), I->getName(), &Dst);<br>
     NF->copyAttributesFrom(I);<br>
     VMap[I] = NF;<br>
   }<br>
<br>
   // Loop over the aliases in the module<br>
-  for (Module::const_alias_iterator I = M.alias_begin(), E = M.alias_end();<br>
+  for (Module::const_alias_iterator I = Src.alias_begin(), E = Src.alias_end();<br>
        I != E; ++I) {<br>
     auto *PTy = cast<PointerType>(I->getType());<br>
     auto *GA =<br>
         GlobalAlias::create(PTy->getElementType(), PTy->getAddressSpace(),<br>
-                            I->getLinkage(), I->getName(), &*New);<br>
+                            I->getLinkage(), I->getName(), &Dst);<br>
     GA->copyAttributesFrom(I);<br>
     VMap[I] = GA;<br>
   }<br>
@@ -77,7 +70,7 @@ llvm::CloneSubModule(const Module &M,<br>
   // Now that all of the things that global variable initializer can refer to<br>
   // have been created, loop through and copy the global variable referrers<br>
   // over...  We also set the attributes on the global now.<br>
-  for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();<br>
+  for (Module::const_global_iterator I = Src.global_begin(), E = Src.global_end();<br>
        I != E; ++I) {<br>
     GlobalVariable &GV = *cast<GlobalVariable>(VMap[I]);<br>
     HandleGlobalVariable(GV, *I, VMap);<br>
@@ -85,13 +78,13 @@ llvm::CloneSubModule(const Module &M,<br>
<br>
   // Similarly, copy over function bodies now...<br>
   //<br>
-  for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) {<br>
+  for (Module::const_iterator I = Src.begin(), E = Src.end(); I != E; ++I) {<br>
     Function &F = *cast<Function>(VMap[I]);<br>
     HandleFunction(F, *I, VMap);<br>
   }<br>
<br>
   // And aliases<br>
-  for (Module::const_alias_iterator I = M.alias_begin(), E = M.alias_end();<br>
+  for (Module::const_alias_iterator I = Src.alias_begin(), E = Src.alias_end();<br>
        I != E; ++I) {<br>
     GlobalAlias *GA = cast<GlobalAlias>(VMap[I]);<br>
     if (const Constant *C = I->getAliasee())<br>
@@ -99,14 +92,13 @@ llvm::CloneSubModule(const Module &M,<br>
   }<br>
<br>
   // And named metadata....<br>
-  for (Module::const_named_metadata_iterator I = M.named_metadata_begin(),<br>
-                                             E = M.named_metadata_end();<br>
+  for (Module::const_named_metadata_iterator I = Src.named_metadata_begin(),<br>
+                                             E = Src.named_metadata_end();<br>
        I != E; ++I) {<br>
     const NamedMDNode &NMD = *I;<br>
-    NamedMDNode *NewNMD = New->getOrInsertNamedMetadata(NMD.getName());<br>
+    NamedMDNode *NewNMD = Dst.getOrInsertNamedMetadata(NMD.getName());<br>
     for (unsigned i = 0, e = NMD.getNumOperands(); i != e; ++i)<br>
       NewNMD->addOperand(MapMetadata(NMD.getOperand(i), VMap));<br>
   }<br>
<br>
-  return New;<br>
 }<br>
<br>
Modified: llvm/trunk/lib/ExecutionEngine/Orc/IndirectionUtils.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/IndirectionUtils.cpp?rev=229461&r1=229460&r2=229461&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/IndirectionUtils.cpp?rev=229461&r1=229460&r2=229461&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/ExecutionEngine/Orc/IndirectionUtils.cpp (original)<br>
+++ llvm/trunk/lib/ExecutionEngine/Orc/IndirectionUtils.cpp Mon Feb 16 19:18:38 2015<br>
@@ -9,149 +9,101 @@ using namespace llvm;<br>
<br>
 namespace llvm {<br>
<br>
-JITIndirections makeCallsSingleIndirect(<br>
-    Module &M, const std::function<bool(const Function &)> &ShouldIndirect,<br>
-    const char *JITImplSuffix, const char *JITAddrSuffix) {<br>
-  std::vector<Function *> Worklist;<br>
-  std::vector<std::string> FuncNames;<br>
-<br>
-  for (auto &F : M)<br>
-    if (ShouldIndirect(F) && (F.user_begin() != F.user_end())) {<br>
-      Worklist.push_back(&F);<br>
-      FuncNames.push_back(F.getName());<br>
-    }<br>
-<br>
-  for (auto *F : Worklist) {<br>
-    GlobalVariable *FImplAddr = new GlobalVariable(<br>
-        M, F->getType(), false, GlobalValue::ExternalLinkage,<br>
-        Constant::getNullValue(F->getType()), F->getName() + JITAddrSuffix,<br>
-        nullptr, GlobalValue::NotThreadLocal, 0, true);<br>
-    FImplAddr->setVisibility(GlobalValue::HiddenVisibility);<br>
-<br>
-    for (auto *U : F->users()) {<br>
-      assert(isa<Instruction>(U) && "Cannot indirect non-instruction use");<br>
-      IRBuilder<> Builder(cast<Instruction>(U));<br>
-      U->replaceUsesOfWith(F, Builder.CreateLoad(FImplAddr));<br>
-    }<br>
-  }<br>
+GlobalVariable* createImplPointer(Function &F, const Twine &Name,<br>
+                                  Constant *Initializer) {<br>
+  assert(F.getParent() && "Function isn't in a module.");<br>
+  if (!Initializer)<br>
+    Initializer = Constant::getNullValue(F.getType());<br>
+  Module &M = *F.getParent();<br>
+  return new GlobalVariable(M, F.getType(), false, GlobalValue::ExternalLinkage,<br>
+                            Initializer, Name, nullptr,<br>
+                            GlobalValue::NotThreadLocal, 0, true);<br>
+}<br>
<br>
-  return JITIndirections(<br>
-      FuncNames, [=](StringRef S) -> std::string { return std::string(S); },<br>
-      [=](StringRef S)<br>
-          -> std::string { return std::string(S) + JITAddrSuffix; });<br>
+void makeStub(Function &F, GlobalVariable &ImplPointer) {<br>
+  assert(F.isDeclaration() && "Can't turn a definition into a stub.");<br>
+  assert(F.getParent() && "Function isn't in a module.");<br>
+  Module &M = *F.getParent();<br>
+  BasicBlock *EntryBlock = BasicBlock::Create(M.getContext(), "entry", &F);<br>
+  IRBuilder<> Builder(EntryBlock);<br>
+  LoadInst *ImplAddr = Builder.CreateLoad(&ImplPointer);<br>
+  std::vector<Value*> CallArgs;<br>
+  for (auto &A : F.args())<br>
+    CallArgs.push_back(&A);<br>
+  CallInst *Call = Builder.CreateCall(ImplAddr, CallArgs);<br>
+  Call->setTailCall();<br>
+  Builder.CreateRet(Call);<br>
 }<br>
<br>
-JITIndirections makeCallsDoubleIndirect(<br>
-    Module &M, const std::function<bool(const Function &)> &ShouldIndirect,<br>
-    const char *JITImplSuffix, const char *JITAddrSuffix) {<br>
-<br>
-  std::vector<Function *> Worklist;<br>
-  std::vector<std::string> FuncNames;<br>
-<br>
-  for (auto &F : M)<br>
-    if (!F.isDeclaration() && !F.hasAvailableExternallyLinkage() &&<br>
-        ShouldIndirect(F))<br>
-      Worklist.push_back(&F);<br>
-<br>
-  for (auto *F : Worklist) {<br>
-    std::string OrigName = F->getName();<br>
-    F->setName(OrigName + JITImplSuffix);<br>
-    FuncNames.push_back(OrigName);<br>
-<br>
-    GlobalVariable *FImplAddr = new GlobalVariable(<br>
-        M, F->getType(), false, GlobalValue::ExternalLinkage,<br>
-        Constant::getNullValue(F->getType()), OrigName + JITAddrSuffix, nullptr,<br>
-        GlobalValue::NotThreadLocal, 0, true);<br>
-    FImplAddr->setVisibility(GlobalValue::HiddenVisibility);<br>
-<br>
-    Function *FRedirect =<br>
-        Function::Create(F->getFunctionType(), F->getLinkage(), OrigName, &M);<br>
-<br>
-    F->replaceAllUsesWith(FRedirect);<br>
-<br>
-    BasicBlock *EntryBlock =<br>
-        BasicBlock::Create(M.getContext(), "entry", FRedirect);<br>
-<br>
-    IRBuilder<> Builder(EntryBlock);<br>
-    LoadInst *FImplLoadedAddr = Builder.CreateLoad(FImplAddr);<br>
-<br>
-    std::vector<Value *> CallArgs;<br>
-    for (Value &Arg : FRedirect->args())<br>
-      CallArgs.push_back(&Arg);<br>
-    CallInst *Call = Builder.CreateCall(FImplLoadedAddr, CallArgs);<br>
-    Call->setTailCall();<br>
-    Builder.CreateRet(Call);<br>
-  }<br>
+void partition(Module &M, const ModulePartitionMap &PMap) {<br>
<br>
-  return JITIndirections(<br>
-      FuncNames, [=](StringRef S)<br>
-                     -> std::string { return std::string(S) + JITImplSuffix; },<br>
-      [=](StringRef S)<br>
-          -> std::string { return std::string(S) + JITAddrSuffix; });<br>
-}<br>
+  for (auto &KVPair : PMap) {<br>
<br>
-std::vector<std::unique_ptr<Module>><br>
-explode(const Module &OrigMod,<br>
-        const std::function<bool(const Function &)> &ShouldExtract) {<br>
-<br>
-  std::vector<std::unique_ptr<Module>> NewModules;<br>
-<br>
-  // Split all the globals, non-indirected functions, etc. into a single module.<br>
-  auto ExtractGlobalVars = [&](GlobalVariable &New, const GlobalVariable &Orig,<br>
-                               ValueToValueMapTy &VMap) {<br>
-    copyGVInitializer(New, Orig, VMap);<br>
-    if (New.getLinkage() == GlobalValue::PrivateLinkage) {<br>
-      New.setLinkage(GlobalValue::ExternalLinkage);<br>
-      New.setVisibility(GlobalValue::HiddenVisibility);<br>
-    }<br>
-  };<br>
+    auto ExtractGlobalVars =<br>
+      [&](GlobalVariable &New, const GlobalVariable &Orig,<br>
+          ValueToValueMapTy &VMap) {<br>
+        if (KVPair.second.count(&Orig)) {<br>
+          copyGVInitializer(New, Orig, VMap);<br>
+        }<br>
+        if (New.getLinkage() == GlobalValue::PrivateLinkage) {<br>
+          New.setLinkage(GlobalValue::ExternalLinkage);<br>
+          New.setVisibility(GlobalValue::HiddenVisibility);<br>
+        }<br>
+      };<br>
<br>
-  auto ExtractNonImplFunctions =<br>
+    auto ExtractFunctions =<br>
       [&](Function &New, const Function &Orig, ValueToValueMapTy &VMap) {<br>
-        if (!ShouldExtract(New))<br>
+        if (KVPair.second.count(&Orig))<br>
           copyFunctionBody(New, Orig, VMap);<br>
+        if (New.getLinkage() == GlobalValue::InternalLinkage) {<br>
+          New.setLinkage(GlobalValue::ExternalLinkage);<br>
+          New.setVisibility(GlobalValue::HiddenVisibility);<br>
+        }<br>
       };<br>
<br>
-  NewModules.push_back(CloneSubModule(OrigMod, ExtractGlobalVars,<br>
-                                      ExtractNonImplFunctions, true));<br>
+    CloneSubModule(*KVPair.first, M, ExtractGlobalVars, ExtractFunctions,<br>
+                   false);<br>
+  }<br>
+}<br>
+<br>
+FullyPartitionedModule fullyPartition(Module &M) {<br>
+  FullyPartitionedModule MP;<br>
<br>
-  // Preserve initializers for Common linkage vars, and make private linkage<br>
-  // globals external: they are now provided by the globals module extracted<br>
-  // above.<br>
-  auto DropGlobalVars = [&](GlobalVariable &New, const GlobalVariable &Orig,<br>
-                            ValueToValueMapTy &VMap) {<br>
-    if (New.getLinkage() == GlobalValue::CommonLinkage)<br>
-      copyGVInitializer(New, Orig, VMap);<br>
-    else if (New.getLinkage() == GlobalValue::PrivateLinkage)<br>
-      New.setLinkage(GlobalValue::ExternalLinkage);<br>
-  };<br>
-<br>
-  // Split each 'impl' function out in to its own module.<br>
-  for (const auto &Func : OrigMod) {<br>
-    if (Func.isDeclaration() || !ShouldExtract(Func))<br>
-      continue;<br>
+  ModulePartitionMap PMap;<br>
<br>
-    auto ExtractNamedFunction =<br>
-        [&](Function &New, const Function &Orig, ValueToValueMapTy &VMap) {<br>
-          if (New.getName() == Func.getName())<br>
-            copyFunctionBody(New, Orig, VMap);<br>
-        };<br>
+  for (auto &F : M) {<br>
<br>
-    NewModules.push_back(<br>
-        CloneSubModule(OrigMod, DropGlobalVars, ExtractNamedFunction, false));<br>
-  }<br>
+    if (F.isDeclaration())<br>
+      continue;<br>
<br>
-  return NewModules;<br>
-}<br>
+    std::string NewModuleName = (M.getName() + "." + F.getName()).str();<br>
+    MP.Functions.push_back(<br>
+      llvm::make_unique<Module>(NewModuleName, M.getContext()));<br>
+    MP.Functions.back()->setDataLayout(M.getDataLayout());<br>
+    PMap[MP.Functions.back().get()].insert(&F);<br>
+  }<br>
<br>
-std::vector<std::unique_ptr<Module>><br>
-explode(const Module &OrigMod, const JITIndirections &Indirections) {<br>
-  std::set<std::string> ImplNames;<br>
+  MP.GlobalVars =<br>
+    llvm::make_unique<Module>((M.getName() + ".globals_and_stubs").str(),<br>
+                              M.getContext());<br>
+  MP.GlobalVars->setDataLayout(M.getDataLayout());<br>
+<br>
+  MP.Commons =<br>
+    llvm::make_unique<Module>((M.getName() + ".commons").str(), M.getContext());<br>
+  MP.Commons->setDataLayout(M.getDataLayout());<br>
+<br>
+  // Make sure there's at least an empty set for the stubs map or we'll fail<br>
+  // to clone anything for it (including the decls).<br>
+  PMap[MP.GlobalVars.get()] = ModulePartitionMap::mapped_type();<br>
+  for (auto &GV : M.globals())<br>
+    if (GV.getLinkage() == GlobalValue::CommonLinkage)<br>
+      PMap[MP.Commons.get()].insert(&GV);<br>
+    else<br>
+      PMap[MP.GlobalVars.get()].insert(&GV);<br>
<br>
-  for (const auto &FuncName : Indirections.IndirectedNames)<br>
-    ImplNames.insert(Indirections.GetImplName(FuncName));<br>
+  partition(M, PMap);<br>
<br>
-  return explode(<br>
-      OrigMod, [&](const Function &F) { return ImplNames.count(F.getName()); });<br>
+  return MP;<br>
 }<br>
+<br>
 }<br>
<br>
Modified: llvm/trunk/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp?rev=229461&r1=229460&r2=229461&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp?rev=229461&r1=229460&r2=229461&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp (original)<br>
+++ llvm/trunk/lib/ExecutionEngine/Orc/OrcTargetSupport.cpp Mon Feb 16 19:18:38 2015<br>
@@ -1,14 +1,11 @@<br>
 #include "llvm/ADT/Triple.h"<br>
-#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"<br>
+#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"<br>
 #include <array><br>
<br>
 using namespace llvm;<br>
<br>
 namespace {<br>
<br>
-const char *JITCallbackFuncName = "call_jit_for_lazy_compile";<br>
-const char *JITCallbackIndexLabelPrefix = "jit_resolve_";<br>
-<br>
 std::array<const char *, 12> X86GPRsToSave = {{<br>
     "rbp", "rbx", "r12", "r13", "r14", "r15", // Callee saved.<br>
     "rdi", "rsi", "rdx", "rcx", "r8", "r9",   // Int args.<br>
@@ -41,61 +38,90 @@ template <typename OStream> void restore<br>
     OS << "  popq    %" << X86GPRsToSave[X86GPRsToSave.size() - i - 1] << "\n";<br>
 }<br>
<br>
-uint64_t call_jit_for_fn(JITResolveCallbackHandler *J, uint64_t FuncIdx) {<br>
-  return J->resolve(FuncIdx);<br>
+template <typename TargetT><br>
+uint64_t executeCompileCallback(JITCompileCallbackManagerBase<TargetT> *JCBM,<br>
+                                TargetAddress CallbackID) {<br>
+  return JCBM->executeCompileCallback(CallbackID);<br>
 }<br>
+<br>
 }<br>
<br>
 namespace llvm {<br>
<br>
-std::string getJITResolveCallbackIndexLabel(unsigned I) {<br>
-  std::ostringstream LabelStream;<br>
-  LabelStream << JITCallbackIndexLabelPrefix << I;<br>
-  return LabelStream.str();<br>
-}<br>
+const char* OrcX86_64::ResolverBlockName = "orc_resolver_block";<br>
<br>
-void insertX86CallbackAsm(Module &M, JITResolveCallbackHandler &J) {<br>
+void OrcX86_64::insertResolverBlock(<br>
+                               Module &M,<br>
+                               JITCompileCallbackManagerBase<OrcX86_64> &JCBM) {<br>
   uint64_t CallbackAddr =<br>
-      static_cast<uint64_t>(reinterpret_cast<uintptr_t>(call_jit_for_fn));<br>
+      static_cast<uint64_t>(<br>
+        reinterpret_cast<uintptr_t>(executeCompileCallback<OrcX86_64>));<br>
<br>
-  std::ostringstream JITCallbackAsm;<br>
+  std::ostringstream AsmStream;<br>
   Triple TT(M.getTargetTriple());<br>
<br>
   if (TT.getOS() == Triple::Darwin)<br>
-    JITCallbackAsm << ".section __TEXT,__text,regular,pure_instructions\n"<br>
-                   << ".align 4, 0x90\n";<br>
+    AsmStream << ".section __TEXT,__text,regular,pure_instructions\n"<br>
+              << ".align 4, 0x90\n";<br>
   else<br>
-    JITCallbackAsm << ".text\n"<br>
-                   << ".align 16, 0x90\n";<br>
+    AsmStream << ".text\n"<br>
+              << ".align 16, 0x90\n";<br>
<br>
-  JITCallbackAsm << "jit_object_addr:\n"<br>
-                 << "  .quad " << &J << "\n" << JITCallbackFuncName << ":\n";<br>
+  AsmStream << "jit_callback_manager_addr:\n"<br>
+            << "  .quad " << &JCBM << "\n"<br>
+            << ResolverBlockName << ":\n";<br>
<br>
-  uint64_t ReturnAddrOffset = saveX86Regs(JITCallbackAsm);<br>
+  uint64_t ReturnAddrOffset = saveX86Regs(AsmStream);<br>
<br>
   // Compute index, load object address, and call JIT.<br>
-  JITCallbackAsm << "  movq    " << ReturnAddrOffset << "(%rsp), %rax\n"<br>
-                 << "  leaq    (jit_indices_start+5)(%rip), %rbx\n"<br>
-                 << "  subq    %rbx, %rax\n"<br>
-                 << "  xorq    %rdx, %rdx\n"<br>
-                 << "  movq    $5, %rbx\n"<br>
-                 << "  divq    %rbx\n"<br>
-                 << "  movq    %rax, %rsi\n"<br>
-                 << "  leaq    jit_object_addr(%rip), %rdi\n"<br>
-                 << "  movq    (%rdi), %rdi\n"<br>
-                 << "  movabsq $" << CallbackAddr << ", %rax\n"<br>
-                 << "  callq   *%rax\n"<br>
-                 << "  movq    %rax, " << ReturnAddrOffset << "(%rsp)\n";<br>
-<br>
-  restoreX86Regs(JITCallbackAsm);<br>
-<br>
-  JITCallbackAsm << "  retq\n"<br>
-                 << "jit_indices_start:\n";<br>
-<br>
-  for (JITResolveCallbackHandler::StubIndex I = 0; I < J.getNumFuncs(); ++I)<br>
-    JITCallbackAsm << getJITResolveCallbackIndexLabel(I) << ":\n"<br>
-                   << "  callq " << JITCallbackFuncName << "\n";<br>
+  AsmStream << "  leaq    jit_callback_manager_addr(%rip), %rdi\n"<br>
+            << "  movq    (%rdi), %rdi\n"<br>
+            << "  movq    " << ReturnAddrOffset << "(%rsp), %rsi\n"<br>
+            << "  movabsq $" << CallbackAddr << ", %rax\n"<br>
+            << "  callq   *%rax\n"<br>
+            << "  movq    %rax, " << ReturnAddrOffset << "(%rsp)\n";<br>
+<br>
+  restoreX86Regs(AsmStream);<br>
+<br>
+  AsmStream << "  retq\n";<br>
<br>
-  M.appendModuleInlineAsm(JITCallbackAsm.str());<br>
+  M.appendModuleInlineAsm(AsmStream.str());<br>
 }<br>
+<br>
+OrcX86_64::LabelNameFtor<br>
+OrcX86_64::insertCompileCallbackTrampolines(Module &M,<br>
+                                            TargetAddress ResolverBlockAddr,<br>
+                                            unsigned NumCalls,<br>
+                                            unsigned StartIndex) {<br>
+  const char *ResolverBlockPtrName = "Lorc_resolve_block_addr";<br>
+<br>
+  std::ostringstream AsmStream;<br>
+  Triple TT(M.getTargetTriple());<br>
+<br>
+  if (TT.getOS() == Triple::Darwin)<br>
+    AsmStream << ".section __TEXT,__text,regular,pure_instructions\n"<br>
+              << ".align 4, 0x90\n";<br>
+  else<br>
+    AsmStream << ".text\n"<br>
+              << ".align 16, 0x90\n";<br>
+<br>
+  AsmStream << ResolverBlockPtrName << ":\n"<br>
+            << "  .quad " << ResolverBlockAddr << "\n";<br>
+<br>
+  auto GetLabelName =<br>
+    [=](unsigned I) {<br>
+      std::ostringstream LabelStream;<br>
+      LabelStream << "orc_jcc_" << (StartIndex + I);<br>
+      return LabelStream.str();<br>
+  };<br>
+<br>
+  for (unsigned I = 0; I < NumCalls; ++I)<br>
+    AsmStream << GetLabelName(I) << ":\n"<br>
+              << "  callq *" << ResolverBlockPtrName << "(%rip)\n";<br>
+<br>
+  M.appendModuleInlineAsm(AsmStream.str());<br>
+<br>
+  return GetLabelName;<br>
+}<br>
+<br>
 }<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>