<div dir="ltr">On Thu, Oct 3, 2013 at 5:49 PM, Andrew Kaylor <span dir="ltr"><<a href="mailto:andrew.kaylor@intel.com" target="_blank">andrew.kaylor@intel.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Author: akaylor<br>
Date: Thu Oct  3 19:49:38 2013<br>
New Revision: 191938<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=191938&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=191938&view=rev</a><br>
Log:<br>
Adding support and tests for multiple module handling in lli<br>
<br>
Added:<br>
    llvm/trunk/test/ExecutionEngine/MCJIT/cross-module-a.ll<br>
    llvm/trunk/test/ExecutionEngine/MCJIT/<a href="http://cross-module-b.ir" target="_blank">cross-module-b.ir</a><br>
    llvm/trunk/test/ExecutionEngine/MCJIT/multi-module-a.ll<br></blockquote><div><br></div><div>This test fails under ASan:</div><div><br></div><div><div>==10866==ERROR: AddressSanitizer: heap-use-after-free on address 0x60c00000a5b4 at pc 0x480401 bp 0x7fff14df7a90 sp 0x7fff14df7a88</div>
<div>READ of size 1 at 0x60c00000a5b4 thread T0</div><div>    #0 0x480400 in llvm::RemoteMemoryManager::notifyObjectLoaded(llvm::ExecutionEngine*, llvm::ObjectImage const*) llvm/tools/lli/RemoteMemoryManager.cpp:96</div><div>
    #1 0x59a4de in llvm::MCJIT::NotifyObjectEmitted(llvm::ObjectImage const&) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:516</div><div>    #2 0x59a267 in llvm::MCJIT::generateCodeForModule(llvm::Module*) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:163</div>
<div>    #3 0x59bb14 in llvm::MCJIT::getSymbolAddress(std::string const&, bool) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:316</div><div>    #4 0x59d2ad in llvm::LinkingMemoryManager::getSymbolAddress(std::string const&) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:529</div>
<div>    #5 0x5dfa3d in llvm::RuntimeDyldImpl::resolveExternalSymbols() llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:484</div><div>    #6 0x5df348 in llvm::RuntimeDyldImpl::resolveRelocations() llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:39</div>
<div>    #7 0x59a6a9 in llvm::MCJIT::finalizeLoadedModules() llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:170</div><div>    #8 0x59bc53 in llvm::MCJIT::getFunctionAddress(std::string const&) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:332</div>
<div>    #9 0x487d59 in main llvm/tools/lli/lli.cpp:511</div><div>    #10 0x7f4a386f011c in __libc_start_main</div><div>    #11 0x47ed99 in _start</div><div>0x60c00000a5b4 is located 116 bytes inside of 120-byte region [0x60c00000a540,0x60c00000a5b8)</div>
<div>freed by thread T0 here:</div><div>    #0 0x4757a4 in __interceptor_realloc</div><div>    #1 0x177cee9 in llvm::SmallVectorBase::grow_pod(void*, unsigned long, unsigned long) llvm/lib/Support/SmallVector.cpp:34</div>
<div>    #2 0x4810ef in llvm::SmallVectorTemplateBase<llvm::RemoteMemoryManager::Allocation, true>::push_back(llvm::RemoteMemoryManager::Allocation const&) llvm/include/llvm/ADT/SmallVector.h:357</div><div>    #3 0x47f369 in llvm::RemoteMemoryManager::allocateCodeSection(unsigned long, unsigned int, unsigned int, llvm::StringRef) llvm/tools/lli/RemoteMemoryManager.cpp:39</div>
<div>    #4 0x5e34bb in llvm::RuntimeDyldImpl::emitSection(llvm::ObjectImage&, llvm::object::SectionRef const&, bool) llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:281</div><div>    #5 0x5e1fa0 in llvm::RuntimeDyldImpl::findOrEmitSection(llvm::ObjectImage&, llvm::object::SectionRef const&, bool, std::map<llvm::object::SectionRef, unsigned int, std::less<llvm::object::SectionRef>, std::allocator<std::pair<llvm::object::SectionRef const, unsigned int> > >&) llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:337</div>
<div>    #6 0x5e152c in llvm::RuntimeDyldImpl::loadObject(llvm::ObjectBuffer*) llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:163</div><div>    #7 0x5e49c1 in llvm::RuntimeDyld::loadObject(llvm::ObjectBuffer*) llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:562</div>
<div>    #8 0x59a1ee in llvm::MCJIT::generateCodeForModule(llvm::Module*) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:155</div><div>    #9 0x59bb14 in llvm::MCJIT::getSymbolAddress(std::string const&, bool) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:316</div>
<div>    #10 0x59d2ad in llvm::LinkingMemoryManager::getSymbolAddress(std::string const&) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:529</div><div>    #11 0x5dfa3d in llvm::RuntimeDyldImpl::resolveExternalSymbols() llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:484</div>
<div>    #12 0x5df348 in llvm::RuntimeDyldImpl::resolveRelocations() llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:39</div><div>    #13 0x59a6a9 in llvm::MCJIT::finalizeLoadedModules() llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:170</div>
<div>    #14 0x59bc53 in llvm::MCJIT::getFunctionAddress(std::string const&) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:332</div><div>    #15 0x487d59 in main llvm/tools/lli/lli.cpp:511</div><div>    #16 0x7f4a386f011c in __libc_start_main</div>
<div>previously allocated by thread T0 here:</div><div>    #0 0x475575 in __interceptor_malloc</div><div>    #1 0x177cef9 in llvm::SmallVectorBase::grow_pod(void*, unsigned long, unsigned long) llvm/lib/Support/SmallVector.cpp:28</div>
<div>    #2 0x4810ef in llvm::SmallVectorTemplateBase<llvm::RemoteMemoryManager::Allocation, true>::push_back(llvm::RemoteMemoryManager::Allocation const&) llvm/include/llvm/ADT/SmallVector.h:357</div><div>    #3 0x47f369 in llvm::RemoteMemoryManager::allocateCodeSection(unsigned long, unsigned int, unsigned int, llvm::StringRef) llvm/tools/lli/RemoteMemoryManager.cpp:39</div>
<div>    #4 0x5e34bb in llvm::RuntimeDyldImpl::emitSection(llvm::ObjectImage&, llvm::object::SectionRef const&, bool) llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:281</div><div>    #5 0x5e1fa0 in llvm::RuntimeDyldImpl::findOrEmitSection(llvm::ObjectImage&, llvm::object::SectionRef const&, bool, std::map<llvm::object::SectionRef, unsigned int, std::less<llvm::object::SectionRef>, std::allocator<std::pair<llvm::object::SectionRef const, unsigned int> > >&) llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:337</div>
<div>    #6 0x5e0b04 in llvm::RuntimeDyldImpl::loadObject(llvm::ObjectBuffer*) llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:130</div><div>    #7 0x5e49c1 in llvm::RuntimeDyld::loadObject(llvm::ObjectBuffer*) llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:562</div>
<div>    #8 0x59a1ee in llvm::MCJIT::generateCodeForModule(llvm::Module*) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:155</div><div>    #9 0x59bb14 in llvm::MCJIT::getSymbolAddress(std::string const&, bool) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:316</div>
<div>    #10 0x59d2ad in llvm::LinkingMemoryManager::getSymbolAddress(std::string const&) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:529</div><div>    #11 0x5dfa3d in llvm::RuntimeDyldImpl::resolveExternalSymbols() llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:484</div>
<div>    #12 0x5df348 in llvm::RuntimeDyldImpl::resolveRelocations() llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp:39</div><div>    #13 0x59a6a9 in llvm::MCJIT::finalizeLoadedModules() llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:170</div>
<div>    #14 0x59bc53 in llvm::MCJIT::getFunctionAddress(std::string const&) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp:332</div><div>    #15 0x487d59 in main llvm/tools/lli/lli.cpp:511</div><div>    #16 0x7f4a386f011c in __libc_start_main</div>
<div>SUMMARY: AddressSanitizer: heap-use-after-free llvm/tools/lli/RemoteMemoryManager.cpp:96 llvm::RemoteMemoryManager::notifyObjectLoaded(llvm::ExecutionEngine*, llvm::ObjectImage const*)</div><div>Shadow bytes around the buggy address:</div>
<div>  0x0c187fff9460: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd</div><div>  0x0c187fff9470: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd</div><div>  0x0c187fff9480: fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa fa</div>
<div>  0x0c187fff9490: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa</div><div>  0x0c187fff94a0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd</div><div>=>0x0c187fff94b0: fd fd fd fd fd fd[fd]fa fa fa fa fa fa fa fa fa</div>
<div>  0x0c187fff94c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd</div><div>  0x0c187fff94d0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd</div><div>  0x0c187fff94e0: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa</div>
<div>  0x0c187fff94f0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd</div><div>  0x0c187fff9500: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd</div><div>Shadow byte legend (one shadow byte represents 8 application bytes):</div>
<div>  Addressable:           00</div><div>  Partially addressable: 01 02 03 04 05 06 07 </div><div>  Heap left redzone:     fa</div><div>  Heap right redzone:    fb</div><div>  Freed heap region:     fd</div><div>  Stack left redzone:    f1</div>
<div>  Stack mid redzone:     f2</div><div>  Stack right redzone:   f3</div><div>  Stack partial redzone: f4</div><div>  Stack after return:    f5</div><div>  Stack use after scope: f8</div><div>  Global redzone:        f9</div>
<div>  Global init order:     f6</div><div>  Poisoned by user:      f7</div><div>  ASan internal:         fe</div><div>==10866==ABORTING</div></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

    llvm/trunk/test/ExecutionEngine/MCJIT/<a href="http://multi-module-b.ir" target="_blank">multi-module-b.ir</a><br>
    llvm/trunk/test/ExecutionEngine/MCJIT/<a href="http://multi-module-c.ir" target="_blank">multi-module-c.ir</a><br>
    llvm/trunk/test/ExecutionEngine/MCJIT/remote/cross-module-a.ll<br>
    llvm/trunk/test/ExecutionEngine/MCJIT/remote/<a href="http://cross-module-b.ir" target="_blank">cross-module-b.ir</a><br>
    llvm/trunk/test/ExecutionEngine/MCJIT/remote/multi-module-a.ll<br>
    llvm/trunk/test/ExecutionEngine/MCJIT/remote/<a href="http://multi-module-b.ir" target="_blank">multi-module-b.ir</a><br>
    llvm/trunk/test/ExecutionEngine/MCJIT/remote/<a href="http://multi-module-c.ir" target="_blank">multi-module-c.ir</a><br>
    llvm/trunk/tools/lli/RemoteMemoryManager.cpp<br>
      - copied, changed from r191860, llvm/trunk/tools/lli/RecordingMemoryManager.cpp<br>
    llvm/trunk/tools/lli/RemoteMemoryManager.h<br>
      - copied, changed from r191860, llvm/trunk/tools/lli/RecordingMemoryManager.h<br>
Removed:<br>
    llvm/trunk/tools/lli/RecordingMemoryManager.cpp<br>
    llvm/trunk/tools/lli/RecordingMemoryManager.h<br>
Modified:<br>
    llvm/trunk/include/llvm/ExecutionEngine/RTDyldMemoryManager.h<br>
    llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.cpp<br>
    llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.h<br>
    llvm/trunk/tools/lli/CMakeLists.txt<br>
    llvm/trunk/tools/lli/lli.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/ExecutionEngine/RTDyldMemoryManager.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/RTDyldMemoryManager.h?rev=191938&r1=191937&r2=191938&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ExecutionEngine/RTDyldMemoryManager.h?rev=191938&r1=191937&r2=191938&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/include/llvm/ExecutionEngine/RTDyldMemoryManager.h (original)<br>
+++ llvm/trunk/include/llvm/ExecutionEngine/RTDyldMemoryManager.h Thu Oct  3 19:49:38 2013<br>
@@ -21,6 +21,9 @@<br>
<br>
 namespace llvm {<br>
<br>
+class ExecutionEngine;<br>
+class ObjectImage;<br>
+<br>
 // RuntimeDyld clients often want to handle the memory management of<br>
 // what gets placed where. For JIT clients, this is the subset of<br>
 // JITMemoryManager required for dynamic loading of binaries.<br>
@@ -41,7 +44,7 @@ public:<br>
   virtual uint8_t *allocateCodeSection(<br>
     uintptr_t Size, unsigned Alignment, unsigned SectionID,<br>
     StringRef SectionName) = 0;<br>
-<br>
+<br>
   /// Allocate a memory block of (at least) the given size suitable for data.<br>
   /// The SectionID is a unique identifier assigned by the JIT engine, and<br>
   /// optionally recorded by the memory manager to access a loaded section.<br>
@@ -63,11 +66,24 @@ public:<br>
   /// found, this function returns a null pointer. Otherwise, it prints a<br>
   /// message to stderr and aborts.<br>
   ///<br>
-  /// This function is deprecated for memory managers used to be used with<br>
+  /// This function is deprecated for memory managers to be used with<br>
   /// MCJIT or RuntimeDyld.  Use getSymbolAddress instead.<br>
   virtual void *getPointerToNamedFunction(const std::string &Name,<br>
                                           bool AbortOnFailure = true);<br>
<br>
+  /// This method is called after an object has been loaded into memory but<br>
+  /// before relocations are applied to the loaded sections.  The object load<br>
+  /// may have been initiated by MCJIT to resolve an external symbol for another<br>
+  /// object that is being finalized.  In that case, the object about which<br>
+  /// the memory manager is being notified will be finalized immediately after<br>
+  /// the memory manager returns from this call.<br>
+  ///<br>
+  /// Memory managers which are preparing code for execution in an external<br>
+  /// address space can use this call to remap the section addresses for the<br>
+  /// newly loaded object.<br>
+  virtual void notifyObjectLoaded(ExecutionEngine *EE,<br>
+                                  const ObjectImage *) {}<br>
+<br>
   /// This method is called when object loading is complete and section page<br>
   /// permissions can be applied.  It is up to the memory manager implementation<br>
   /// to decide whether or not to act on this method.  The memory manager will<br>
<br>
Modified: llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.cpp?rev=191938&r1=191937&r2=191938&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.cpp?rev=191938&r1=191937&r2=191938&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.cpp (original)<br>
+++ llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.cpp Thu Oct  3 19:49:38 2013<br>
@@ -513,6 +513,7 @@ void MCJIT::UnregisterJITEventListener(J<br>
 }<br>
 void MCJIT::NotifyObjectEmitted(const ObjectImage& Obj) {<br>
   MutexGuard locked(lock);<br>
+  MemMgr.notifyObjectLoaded(this, &Obj);<br>
   for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) {<br>
     EventListeners[I]->NotifyObjectEmitted(Obj);<br>
   }<br>
<br>
Modified: llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.h?rev=191938&r1=191937&r2=191938&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.h?rev=191938&r1=191937&r2=191938&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.h (original)<br>
+++ llvm/trunk/lib/ExecutionEngine/MCJIT/MCJIT.h Thu Oct  3 19:49:38 2013<br>
@@ -46,6 +46,11 @@ public:<br>
                                          SectionID, SectionName, IsReadOnly);<br>
   }<br>
<br>
+  virtual void notifyObjectLoaded(ExecutionEngine *EE,<br>
+                                  const ObjectImage *Obj) {<br>
+    ClientMM->notifyObjectLoaded(EE, Obj);<br>
+  }<br>
+<br>
   virtual void registerEHFrames(StringRef SectionData) {<br>
     ClientMM->registerEHFrames(SectionData);<br>
   }<br>
<br>
Added: llvm/trunk/test/ExecutionEngine/MCJIT/cross-module-a.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/cross-module-a.ll?rev=191938&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/cross-module-a.ll?rev=191938&view=auto</a><br>

==============================================================================<br>
--- llvm/trunk/test/ExecutionEngine/MCJIT/cross-module-a.ll (added)<br>
+++ llvm/trunk/test/ExecutionEngine/MCJIT/cross-module-a.ll Thu Oct  3 19:49:38 2013<br>
@@ -0,0 +1,13 @@<br>
+; RUN: %lli_mcjit -extra-modules=%p/<a href="http://cross-module-b.ir" target="_blank">cross-module-b.ir</a> %s > /dev/null<br>
+<br>
+declare i32 @FB()<br>
+<br>
+define i32 @FA() {<br>
+  ret i32 0<br>
+}<br>
+<br>
+define i32 @main() {<br>
+  %r = call i32 @FB( )   ; <i32> [#uses=1]<br>
+  ret i32 %r<br>
+}<br>
+<br>
<br>
Added: llvm/trunk/test/ExecutionEngine/MCJIT/<a href="http://cross-module-b.ir" target="_blank">cross-module-b.ir</a><br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/cross-module-b.ir?rev=191938&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/cross-module-b.ir?rev=191938&view=auto</a><br>

==============================================================================<br>
--- llvm/trunk/test/ExecutionEngine/MCJIT/<a href="http://cross-module-b.ir" target="_blank">cross-module-b.ir</a> (added)<br>
+++ llvm/trunk/test/ExecutionEngine/MCJIT/<a href="http://cross-module-b.ir" target="_blank">cross-module-b.ir</a> Thu Oct  3 19:49:38 2013<br>
@@ -0,0 +1,7 @@<br>
+declare i32 @FA()<br>
+<br>
+define i32 @FB() {<br>
+  %r = call i32 @FA( )   ; <i32> [#uses=1]<br>
+  ret i32 %r<br>
+}<br>
+<br>
<br>
Added: llvm/trunk/test/ExecutionEngine/MCJIT/multi-module-a.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/multi-module-a.ll?rev=191938&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/multi-module-a.ll?rev=191938&view=auto</a><br>

==============================================================================<br>
--- llvm/trunk/test/ExecutionEngine/MCJIT/multi-module-a.ll (added)<br>
+++ llvm/trunk/test/ExecutionEngine/MCJIT/multi-module-a.ll Thu Oct  3 19:49:38 2013<br>
@@ -0,0 +1,9 @@<br>
+; RUN: %lli_mcjit -extra-modules=%p/<a href="http://multi-module-b.ir" target="_blank">multi-module-b.ir</a>,%p/<a href="http://multi-module-c.ir" target="_blank">multi-module-c.ir</a> %s > /dev/null<br>
+<br>
+declare i32 @FB()<br>
+<br>
+define i32 @main() {<br>
+  %r = call i32 @FB( )   ; <i32> [#uses=1]<br>
+  ret i32 %r<br>
+}<br>
+<br>
<br>
Added: llvm/trunk/test/ExecutionEngine/MCJIT/<a href="http://multi-module-b.ir" target="_blank">multi-module-b.ir</a><br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/multi-module-b.ir?rev=191938&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/multi-module-b.ir?rev=191938&view=auto</a><br>

==============================================================================<br>
--- llvm/trunk/test/ExecutionEngine/MCJIT/<a href="http://multi-module-b.ir" target="_blank">multi-module-b.ir</a> (added)<br>
+++ llvm/trunk/test/ExecutionEngine/MCJIT/<a href="http://multi-module-b.ir" target="_blank">multi-module-b.ir</a> Thu Oct  3 19:49:38 2013<br>
@@ -0,0 +1,7 @@<br>
+declare i32 @FC()<br>
+<br>
+define i32 @FB() {<br>
+  %r = call i32 @FC( )   ; <i32> [#uses=1]<br>
+  ret i32 %r<br>
+}<br>
+<br>
<br>
Added: llvm/trunk/test/ExecutionEngine/MCJIT/<a href="http://multi-module-c.ir" target="_blank">multi-module-c.ir</a><br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/multi-module-c.ir?rev=191938&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/multi-module-c.ir?rev=191938&view=auto</a><br>

==============================================================================<br>
--- llvm/trunk/test/ExecutionEngine/MCJIT/<a href="http://multi-module-c.ir" target="_blank">multi-module-c.ir</a> (added)<br>
+++ llvm/trunk/test/ExecutionEngine/MCJIT/<a href="http://multi-module-c.ir" target="_blank">multi-module-c.ir</a> Thu Oct  3 19:49:38 2013<br>
@@ -0,0 +1,4 @@<br>
+define i32 @FC() {<br>
+  ret i32 0<br>
+}<br>
+<br>
<br>
Added: llvm/trunk/test/ExecutionEngine/MCJIT/remote/cross-module-a.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/remote/cross-module-a.ll?rev=191938&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/remote/cross-module-a.ll?rev=191938&view=auto</a><br>

==============================================================================<br>
--- llvm/trunk/test/ExecutionEngine/MCJIT/remote/cross-module-a.ll (added)<br>
+++ llvm/trunk/test/ExecutionEngine/MCJIT/remote/cross-module-a.ll Thu Oct  3 19:49:38 2013<br>
@@ -0,0 +1,13 @@<br>
+; RUN: %lli_mcjit -extra-modules=%p/<a href="http://cross-module-b.ir" target="_blank">cross-module-b.ir</a>  -disable-lazy-compilation=true -remote-mcjit -mcjit-remote-process=lli-child-target %s > /dev/null<br>
+<br>
+declare i32 @FB()<br>
+<br>
+define i32 @FA() {<br>
+  ret i32 0<br>
+}<br>
+<br>
+define i32 @main() {<br>
+  %r = call i32 @FB( )   ; <i32> [#uses=1]<br>
+  ret i32 %r<br>
+}<br>
+<br>
<br>
Added: llvm/trunk/test/ExecutionEngine/MCJIT/remote/<a href="http://cross-module-b.ir" target="_blank">cross-module-b.ir</a><br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/remote/cross-module-b.ir?rev=191938&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/remote/cross-module-b.ir?rev=191938&view=auto</a><br>

==============================================================================<br>
--- llvm/trunk/test/ExecutionEngine/MCJIT/remote/<a href="http://cross-module-b.ir" target="_blank">cross-module-b.ir</a> (added)<br>
+++ llvm/trunk/test/ExecutionEngine/MCJIT/remote/<a href="http://cross-module-b.ir" target="_blank">cross-module-b.ir</a> Thu Oct  3 19:49:38 2013<br>
@@ -0,0 +1,7 @@<br>
+declare i32 @FA()<br>
+<br>
+define i32 @FB() {<br>
+  %r = call i32 @FA( )   ; <i32> [#uses=1]<br>
+  ret i32 %r<br>
+}<br>
+<br>
<br>
Added: llvm/trunk/test/ExecutionEngine/MCJIT/remote/multi-module-a.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/remote/multi-module-a.ll?rev=191938&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/remote/multi-module-a.ll?rev=191938&view=auto</a><br>

==============================================================================<br>
--- llvm/trunk/test/ExecutionEngine/MCJIT/remote/multi-module-a.ll (added)<br>
+++ llvm/trunk/test/ExecutionEngine/MCJIT/remote/multi-module-a.ll Thu Oct  3 19:49:38 2013<br>
@@ -0,0 +1,9 @@<br>
+; RUN: %lli_mcjit -extra-modules=%p/<a href="http://multi-module-b.ir" target="_blank">multi-module-b.ir</a>,%p/<a href="http://multi-module-c.ir" target="_blank">multi-module-c.ir</a>  -disable-lazy-compilation=true -remote-mcjit -mcjit-remote-process=lli-child-target %s > /dev/null<br>

+<br>
+declare i32 @FB()<br>
+<br>
+define i32 @main() {<br>
+  %r = call i32 @FB( )   ; <i32> [#uses=1]<br>
+  ret i32 %r<br>
+}<br>
+<br>
<br>
Added: llvm/trunk/test/ExecutionEngine/MCJIT/remote/<a href="http://multi-module-b.ir" target="_blank">multi-module-b.ir</a><br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/remote/multi-module-b.ir?rev=191938&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/remote/multi-module-b.ir?rev=191938&view=auto</a><br>

==============================================================================<br>
--- llvm/trunk/test/ExecutionEngine/MCJIT/remote/<a href="http://multi-module-b.ir" target="_blank">multi-module-b.ir</a> (added)<br>
+++ llvm/trunk/test/ExecutionEngine/MCJIT/remote/<a href="http://multi-module-b.ir" target="_blank">multi-module-b.ir</a> Thu Oct  3 19:49:38 2013<br>
@@ -0,0 +1,7 @@<br>
+declare i32 @FC()<br>
+<br>
+define i32 @FB() {<br>
+  %r = call i32 @FC( )   ; <i32> [#uses=1]<br>
+  ret i32 %r<br>
+}<br>
+<br>
<br>
Added: llvm/trunk/test/ExecutionEngine/MCJIT/remote/<a href="http://multi-module-c.ir" target="_blank">multi-module-c.ir</a><br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/remote/multi-module-c.ir?rev=191938&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ExecutionEngine/MCJIT/remote/multi-module-c.ir?rev=191938&view=auto</a><br>

==============================================================================<br>
--- llvm/trunk/test/ExecutionEngine/MCJIT/remote/<a href="http://multi-module-c.ir" target="_blank">multi-module-c.ir</a> (added)<br>
+++ llvm/trunk/test/ExecutionEngine/MCJIT/remote/<a href="http://multi-module-c.ir" target="_blank">multi-module-c.ir</a> Thu Oct  3 19:49:38 2013<br>
@@ -0,0 +1,4 @@<br>
+define i32 @FC() {<br>
+  ret i32 0<br>
+}<br>
+<br>
<br>
Modified: llvm/trunk/tools/lli/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/CMakeLists.txt?rev=191938&r1=191937&r2=191938&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/CMakeLists.txt?rev=191938&r1=191937&r2=191938&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/tools/lli/CMakeLists.txt (original)<br>
+++ llvm/trunk/tools/lli/CMakeLists.txt Thu Oct  3 19:49:38 2013<br>
@@ -21,7 +21,7 @@ endif( LLVM_USE_INTEL_JITEVENTS )<br>
<br>
 add_llvm_tool(lli<br>
   lli.cpp<br>
-  RecordingMemoryManager.cpp<br>
+  RemoteMemoryManager.cpp<br>
   RemoteTarget.cpp<br>
   RemoteTargetExternal.cpp<br>
   )<br>
<br>
Removed: llvm/trunk/tools/lli/RecordingMemoryManager.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/RecordingMemoryManager.cpp?rev=191937&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/RecordingMemoryManager.cpp?rev=191937&view=auto</a><br>

==============================================================================<br>
--- llvm/trunk/tools/lli/RecordingMemoryManager.cpp (original)<br>
+++ llvm/trunk/tools/lli/RecordingMemoryManager.cpp (removed)<br>
@@ -1,126 +0,0 @@<br>
-//===- RecordingMemoryManager.cpp - Recording memory manager --------------===//<br>
-//<br>
-//                     The LLVM Compiler Infrastructure<br>
-//<br>
-// This file is distributed under the University of Illinois Open Source<br>
-// License. See LICENSE.TXT for details.<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-//<br>
-// This memory manager allocates local storage and keeps a record of each<br>
-// allocation. Iterators are provided for all data and code allocations.<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-#include "RecordingMemoryManager.h"<br>
-using namespace llvm;<br>
-<br>
-RecordingMemoryManager::~RecordingMemoryManager() {<br>
-  for (SmallVectorImpl<Allocation>::iterator<br>
-         I = AllocatedCodeMem.begin(), E = AllocatedCodeMem.end();<br>
-       I != E; ++I)<br>
-    sys::Memory::releaseMappedMemory(I->first);<br>
-  for (SmallVectorImpl<Allocation>::iterator<br>
-         I = AllocatedDataMem.begin(), E = AllocatedDataMem.end();<br>
-       I != E; ++I)<br>
-    sys::Memory::releaseMappedMemory(I->first);<br>
-}<br>
-<br>
-uint8_t *RecordingMemoryManager::<br>
-allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID,<br>
-                    StringRef SectionName) {<br>
-  // The recording memory manager is just a local copy of the remote target.<br>
-  // The alignment requirement is just stored here for later use. Regular<br>
-  // heap storage is sufficient here, but we're using mapped memory to work<br>
-  // around a bug in MCJIT.<br>
-  sys::MemoryBlock Block = allocateSection(Size);<br>
-  AllocatedCodeMem.push_back(Allocation(Block, Alignment));<br>
-  return (uint8_t*)Block.base();<br>
-}<br>
-<br>
-uint8_t *RecordingMemoryManager::<br>
-allocateDataSection(uintptr_t Size, unsigned Alignment,<br>
-                    unsigned SectionID, StringRef SectionName,<br>
-                    bool IsReadOnly) {<br>
-  // The recording memory manager is just a local copy of the remote target.<br>
-  // The alignment requirement is just stored here for later use. Regular<br>
-  // heap storage is sufficient here, but we're using mapped memory to work<br>
-  // around a bug in MCJIT.<br>
-  sys::MemoryBlock Block = allocateSection(Size);<br>
-  AllocatedDataMem.push_back(Allocation(Block, Alignment));<br>
-  return (uint8_t*)Block.base();<br>
-}<br>
-<br>
-sys::MemoryBlock RecordingMemoryManager::allocateSection(uintptr_t Size) {<br>
-  error_code ec;<br>
-  sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size,<br>
-                                                          &Near,<br>
-                                                          sys::Memory::MF_READ |<br>
-                                                          sys::Memory::MF_WRITE,<br>
-                                                          ec);<br>
-  assert(!ec && MB.base());<br>
-<br>
-  // FIXME: This is part of a work around to keep sections near one another<br>
-  // when MCJIT performs relocations after code emission but before<br>
-  // the generated code is moved to the remote target.<br>
-  // Save this address as the basis for our next request<br>
-  Near = MB;<br>
-  return MB;<br>
-}<br>
-<br>
-void RecordingMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); }<br>
-void RecordingMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); }<br>
-void RecordingMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); }<br>
-void RecordingMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); }<br>
-uint8_t *RecordingMemoryManager::getGOTBase() const {<br>
-  llvm_unreachable("Unexpected!");<br>
-  return 0;<br>
-}<br>
-uint8_t *RecordingMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){<br>
-  llvm_unreachable("Unexpected!");<br>
-  return 0;<br>
-}<br>
-uint8_t *RecordingMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize,<br>
-                                              unsigned Alignment) {<br>
-  llvm_unreachable("Unexpected!");<br>
-  return 0;<br>
-}<br>
-void RecordingMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart,<br>
-                                             uint8_t *FunctionEnd) {<br>
-  llvm_unreachable("Unexpected!");<br>
-}<br>
-uint8_t *RecordingMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) {<br>
-  llvm_unreachable("Unexpected!");<br>
-  return 0;<br>
-}<br>
-uint8_t *RecordingMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) {<br>
-  llvm_unreachable("Unexpected!");<br>
-  return 0;<br>
-}<br>
-void RecordingMemoryManager::deallocateFunctionBody(void *Body) {<br>
-  llvm_unreachable("Unexpected!");<br>
-}<br>
-<br>
-static int jit_noop() {<br>
-  return 0;<br>
-}<br>
-<br>
-void *RecordingMemoryManager::getPointerToNamedFunction(const std::string &Name,<br>
-                                                        bool AbortOnFailure) {<br>
-  // We should not invoke parent's ctors/dtors from generated main()!<br>
-  // On Mingw and Cygwin, the symbol __main is resolved to<br>
-  // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors<br>
-  // (and register wrong callee's dtors with atexit(3)).<br>
-  // We expect ExecutionEngine::runStaticConstructorsDestructors()<br>
-  // is called before ExecutionEngine::runFunctionAsMain() is called.<br>
-  if (Name == "__main") return (void*)(intptr_t)&jit_noop;<br>
-<br>
-  // FIXME: Would it be responsible to provide GOT?<br>
-  if (AbortOnFailure) {<br>
-    if (Name == "_GLOBAL_OFFSET_TABLE_")<br>
-      report_fatal_error("Program used external function '" + Name +<br>
-                         "' which could not be resolved!");<br>
-  }<br>
-<br>
-  return NULL;<br>
-}<br>
<br>
Removed: llvm/trunk/tools/lli/RecordingMemoryManager.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/RecordingMemoryManager.h?rev=191937&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/RecordingMemoryManager.h?rev=191937&view=auto</a><br>

==============================================================================<br>
--- llvm/trunk/tools/lli/RecordingMemoryManager.h (original)<br>
+++ llvm/trunk/tools/lli/RecordingMemoryManager.h (removed)<br>
@@ -1,83 +0,0 @@<br>
-//===- RecordingMemoryManager.h - LLI MCJIT recording memory manager ------===//<br>
-//<br>
-//                     The LLVM Compiler Infrastructure<br>
-//<br>
-// This file is distributed under the University of Illinois Open Source<br>
-// License. See LICENSE.TXT for details.<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-//<br>
-// This memory manager allocates local storage and keeps a record of each<br>
-// allocation. Iterators are provided for all data and code allocations.<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-#ifndef RECORDINGMEMORYMANAGER_H<br>
-#define RECORDINGMEMORYMANAGER_H<br>
-<br>
-#include "llvm/ADT/SmallVector.h"<br>
-#include "llvm/ExecutionEngine/JITMemoryManager.h"<br>
-#include "llvm/Support/ErrorHandling.h"<br>
-#include "llvm/Support/Memory.h"<br>
-#include <utility><br>
-<br>
-namespace llvm {<br>
-<br>
-class RecordingMemoryManager : public JITMemoryManager {<br>
-public:<br>
-  typedef std::pair<sys::MemoryBlock, unsigned> Allocation;<br>
-<br>
-private:<br>
-  SmallVector<Allocation, 16> AllocatedDataMem;<br>
-  SmallVector<Allocation, 16> AllocatedCodeMem;<br>
-<br>
-  // FIXME: This is part of a work around to keep sections near one another<br>
-  // when MCJIT performs relocations after code emission but before<br>
-  // the generated code is moved to the remote target.<br>
-  sys::MemoryBlock Near;<br>
-  sys::MemoryBlock allocateSection(uintptr_t Size);<br>
-<br>
-public:<br>
-  RecordingMemoryManager() {}<br>
-  virtual ~RecordingMemoryManager();<br>
-<br>
-  typedef SmallVectorImpl<Allocation>::const_iterator const_data_iterator;<br>
-  typedef SmallVectorImpl<Allocation>::const_iterator const_code_iterator;<br>
-<br>
-  const_data_iterator data_begin() const { return AllocatedDataMem.begin(); }<br>
-  const_data_iterator   data_end() const { return AllocatedDataMem.end(); }<br>
-  const_code_iterator code_begin() const { return AllocatedCodeMem.begin(); }<br>
-  const_code_iterator   code_end() const { return AllocatedCodeMem.end(); }<br>
-<br>
-  uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,<br>
-                               unsigned SectionID, StringRef SectionName);<br>
-<br>
-  uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,<br>
-                               unsigned SectionID, StringRef SectionName,<br>
-                               bool IsReadOnly);<br>
-<br>
-  void *getPointerToNamedFunction(const std::string &Name,<br>
-                                  bool AbortOnFailure = true);<br>
-<br>
-  bool finalizeMemory(std::string *ErrMsg) { return false; }<br>
-<br>
-  // The following obsolete JITMemoryManager calls are stubbed out for<br>
-  // this model.<br>
-  void setMemoryWritable();<br>
-  void setMemoryExecutable();<br>
-  void setPoisonMemory(bool poison);<br>
-  void AllocateGOT();<br>
-  uint8_t *getGOTBase() const;<br>
-  uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize);<br>
-  uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,<br>
-                        unsigned Alignment);<br>
-  void endFunctionBody(const Function *F, uint8_t *FunctionStart,<br>
-                       uint8_t *FunctionEnd);<br>
-  uint8_t *allocateSpace(intptr_t Size, unsigned Alignment);<br>
-  uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment);<br>
-  void deallocateFunctionBody(void *Body);<br>
-};<br>
-<br>
-} // end namespace llvm<br>
-<br>
-#endif<br>
<br>
Copied: llvm/trunk/tools/lli/RemoteMemoryManager.cpp (from r191860, llvm/trunk/tools/lli/RecordingMemoryManager.cpp)<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/RemoteMemoryManager.cpp?p2=llvm/trunk/tools/lli/RemoteMemoryManager.cpp&p1=llvm/trunk/tools/lli/RecordingMemoryManager.cpp&r1=191860&r2=191938&rev=191938&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/RemoteMemoryManager.cpp?p2=llvm/trunk/tools/lli/RemoteMemoryManager.cpp&p1=llvm/trunk/tools/lli/RecordingMemoryManager.cpp&r1=191860&r2=191938&rev=191938&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/tools/lli/RecordingMemoryManager.cpp (original)<br>
+++ llvm/trunk/tools/lli/RemoteMemoryManager.cpp Thu Oct  3 19:49:38 2013<br>
@@ -1,4 +1,4 @@<br>
-//===- RecordingMemoryManager.cpp - Recording memory manager --------------===//<br>
+//===---- RemoteMemoryManager.cpp - Recording memory manager --------------===//<br>
 //<br>
 //                     The LLVM Compiler Infrastructure<br>
 //<br>
@@ -12,21 +12,23 @@<br>
 //<br>
 //===----------------------------------------------------------------------===//<br>
<br>
-#include "RecordingMemoryManager.h"<br>
+#define DEBUG_TYPE "lli"<br>
+#include "RemoteMemoryManager.h"<br>
+#include "llvm/ExecutionEngine/ExecutionEngine.h"<br>
+#include "llvm/ExecutionEngine/ObjectImage.h"<br>
+#include "llvm/Support/Debug.h"<br>
+#include "llvm/Support/Format.h"<br>
+<br>
 using namespace llvm;<br>
<br>
-RecordingMemoryManager::~RecordingMemoryManager() {<br>
-  for (SmallVectorImpl<Allocation>::iterator<br>
-         I = AllocatedCodeMem.begin(), E = AllocatedCodeMem.end();<br>
-       I != E; ++I)<br>
-    sys::Memory::releaseMappedMemory(I->first);<br>
-  for (SmallVectorImpl<Allocation>::iterator<br>
-         I = AllocatedDataMem.begin(), E = AllocatedDataMem.end();<br>
+RemoteMemoryManager::~RemoteMemoryManager() {<br>
+  for (SmallVector<Allocation, 2>::iterator<br>
+         I = AllocatedSections.begin(), E = AllocatedSections.end();<br>
        I != E; ++I)<br>
-    sys::Memory::releaseMappedMemory(I->first);<br>
+    sys::Memory::releaseMappedMemory(I->MB);<br>
 }<br>
<br>
-uint8_t *RecordingMemoryManager::<br>
+uint8_t *RemoteMemoryManager::<br>
 allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID,<br>
                     StringRef SectionName) {<br>
   // The recording memory manager is just a local copy of the remote target.<br>
@@ -34,11 +36,12 @@ allocateCodeSection(uintptr_t Size, unsi<br>
   // heap storage is sufficient here, but we're using mapped memory to work<br>
   // around a bug in MCJIT.<br>
   sys::MemoryBlock Block = allocateSection(Size);<br>
-  AllocatedCodeMem.push_back(Allocation(Block, Alignment));<br>
+  AllocatedSections.push_back( Allocation(Block, Alignment, true) );<br>
+  UnmappedSections.push_back( &AllocatedSections.back() );<br>
   return (uint8_t*)Block.base();<br>
 }<br>
<br>
-uint8_t *RecordingMemoryManager::<br>
+uint8_t *RemoteMemoryManager::<br>
 allocateDataSection(uintptr_t Size, unsigned Alignment,<br>
                     unsigned SectionID, StringRef SectionName,<br>
                     bool IsReadOnly) {<br>
@@ -47,11 +50,12 @@ allocateDataSection(uintptr_t Size, unsi<br>
   // heap storage is sufficient here, but we're using mapped memory to work<br>
   // around a bug in MCJIT.<br>
   sys::MemoryBlock Block = allocateSection(Size);<br>
-  AllocatedDataMem.push_back(Allocation(Block, Alignment));<br>
+  AllocatedSections.push_back( Allocation(Block, Alignment, false) );<br>
+  UnmappedSections.push_back( &AllocatedSections.back() );<br>
   return (uint8_t*)Block.base();<br>
 }<br>
<br>
-sys::MemoryBlock RecordingMemoryManager::allocateSection(uintptr_t Size) {<br>
+sys::MemoryBlock RemoteMemoryManager::allocateSection(uintptr_t Size) {<br>
   error_code ec;<br>
   sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size,<br>
                                                           &Near,<br>
@@ -68,36 +72,136 @@ sys::MemoryBlock RecordingMemoryManager:<br>
   return MB;<br>
 }<br>
<br>
-void RecordingMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); }<br>
-void RecordingMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); }<br>
-void RecordingMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); }<br>
-void RecordingMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); }<br>
-uint8_t *RecordingMemoryManager::getGOTBase() const {<br>
+void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE,<br>
+                                                const ObjectImage *Obj) {<br>
+  // The client should have called setRemoteTarget() before triggering any<br>
+  // code generation.<br>
+  assert(Target);<br>
+  if (!Target)<br>
+    return;<br>
+<br>
+  // FIXME: Make this function thread safe.<br>
+<br>
+  // Lay out our sections in order, with all the code sections first, then<br>
+  // all the data sections.<br>
+  uint64_t CurOffset = 0;<br>
+  unsigned MaxAlign = Target->getPageAlignment();<br>
+  SmallVector<std::pair<const Allocation*, uint64_t>, 16> Offsets;<br>
+  unsigned NumSections = UnmappedSections.size();<br>
+  // We're going to go through the list twice to separate code and data, but<br>
+  // it's a very small list, so that's OK.<br>
+  for (size_t i = 0, e = NumSections; i != e; ++i) {<br>
+    const Allocation *Section = UnmappedSections[i];<br>
+    assert(Section);<br>
+    if (Section->IsCode) {<br>
+      unsigned Size = Section->MB.size();<br>
+      unsigned Align = Section->Alignment;<br>
+      DEBUG(dbgs() << "code region: size " << Size<br>
+                  << ", alignment " << Align << "\n");<br>
+      // Align the current offset up to whatever is needed for the next<br>
+      // section.<br>
+      CurOffset = (CurOffset + Align - 1) / Align * Align;<br>
+      // Save off the address of the new section and allocate its space.<br>
+      Offsets.push_back(std::pair<const Allocation*,uint64_t>(Section,<br>
+                                                              CurOffset));<br>
+      CurOffset += Size;<br>
+    }<br>
+  }<br>
+  // Adjust to keep code and data aligned on seperate pages.<br>
+  CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign;<br>
+  for (size_t i = 0, e = NumSections; i != e; ++i) {<br>
+    const Allocation *Section = UnmappedSections[i];<br>
+    assert(Section);<br>
+    if (!Section->IsCode) {<br>
+      unsigned Size = Section->MB.size();<br>
+      unsigned Align = Section->Alignment;<br>
+      DEBUG(dbgs() << "data region: size " << Size<br>
+                  << ", alignment " << Align << "\n");<br>
+      // Align the current offset up to whatever is needed for the next<br>
+      // section.<br>
+      CurOffset = (CurOffset + Align - 1) / Align * Align;<br>
+      // Save off the address of the new section and allocate its space.<br>
+      Offsets.push_back(std::pair<const Allocation*,uint64_t>(Section,<br>
+                                                              CurOffset));<br>
+      CurOffset += Size;<br>
+    }<br>
+  }<br>
+<br>
+  // Allocate space in the remote target.<br>
+  uint64_t RemoteAddr;<br>
+  if (Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr))<br>
+    report_fatal_error(Target->getErrorMsg());<br>
+<br>
+  // Map the section addresses so relocations will get updated in the local<br>
+  // copies of the sections.<br>
+  for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {<br>
+    uint64_t Addr = RemoteAddr + Offsets[i].second;<br>
+    EE->mapSectionAddress(const_cast<void*>(Offsets[i].first->MB.base()), Addr);<br>
+<br>
+    DEBUG(dbgs() << "  Mapping local: " << Offsets[i].first->MB.base()<br>
+                 << " to remote: 0x" << format("%llx", Addr) << "\n");<br>
+<br>
+    MappedSections[Addr] = Offsets[i].first;<br>
+  }<br>
+<br>
+  UnmappedSections.clear();<br>
+}<br>
+<br>
+bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) {<br>
+  // FIXME: Make this function thread safe.<br>
+  for (DenseMap<uint64_t, const Allocation*>::iterator<br>
+         I = MappedSections.begin(), E = MappedSections.end();<br>
+       I != E; ++I) {<br>
+    uint64_t RemoteAddr = I->first;<br>
+    const Allocation *Section = I->second;<br>
+    if (Section->IsCode) {<br>
+      Target->loadCode(RemoteAddr, Section->MB.base(), Section->MB.size());<br>
+<br>
+      DEBUG(dbgs() << "  loading code: " << Section->MB.base()<br>
+            << " to remote: 0x" << format("%llx", RemoteAddr) << "\n");<br>
+    } else {<br>
+      Target->loadData(RemoteAddr, Section->MB.base(), Section->MB.size());<br>
+<br>
+      DEBUG(dbgs() << "  loading data: " << Section->MB.base()<br>
+            << " to remote: 0x" << format("%llx", RemoteAddr) << "\n");<br>
+    }<br>
+  }<br>
+<br>
+  MappedSections.clear();<br>
+<br>
+  return false;<br>
+}<br>
+<br>
+void RemoteMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); }<br>
+void RemoteMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); }<br>
+void RemoteMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); }<br>
+void RemoteMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); }<br>
+uint8_t *RemoteMemoryManager::getGOTBase() const {<br>
   llvm_unreachable("Unexpected!");<br>
   return 0;<br>
 }<br>
-uint8_t *RecordingMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){<br>
+uint8_t *RemoteMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){<br>
   llvm_unreachable("Unexpected!");<br>
   return 0;<br>
 }<br>
-uint8_t *RecordingMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize,<br>
+uint8_t *RemoteMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize,<br>
                                               unsigned Alignment) {<br>
   llvm_unreachable("Unexpected!");<br>
   return 0;<br>
 }<br>
-void RecordingMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart,<br>
+void RemoteMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart,<br>
                                              uint8_t *FunctionEnd) {<br>
   llvm_unreachable("Unexpected!");<br>
 }<br>
-uint8_t *RecordingMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) {<br>
+uint8_t *RemoteMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) {<br>
   llvm_unreachable("Unexpected!");<br>
   return 0;<br>
 }<br>
-uint8_t *RecordingMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) {<br>
+uint8_t *RemoteMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) {<br>
   llvm_unreachable("Unexpected!");<br>
   return 0;<br>
 }<br>
-void RecordingMemoryManager::deallocateFunctionBody(void *Body) {<br>
+void RemoteMemoryManager::deallocateFunctionBody(void *Body) {<br>
   llvm_unreachable("Unexpected!");<br>
 }<br>
<br>
@@ -105,7 +209,7 @@ static int jit_noop() {<br>
   return 0;<br>
 }<br>
<br>
-void *RecordingMemoryManager::getPointerToNamedFunction(const std::string &Name,<br>
+void *RemoteMemoryManager::getPointerToNamedFunction(const std::string &Name,<br>
                                                         bool AbortOnFailure) {<br>
   // We should not invoke parent's ctors/dtors from generated main()!<br>
   // On Mingw and Cygwin, the symbol __main is resolved to<br>
<br>
Copied: llvm/trunk/tools/lli/RemoteMemoryManager.h (from r191860, llvm/trunk/tools/lli/RecordingMemoryManager.h)<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/RemoteMemoryManager.h?p2=llvm/trunk/tools/lli/RemoteMemoryManager.h&p1=llvm/trunk/tools/lli/RecordingMemoryManager.h&r1=191860&r2=191938&rev=191938&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/RemoteMemoryManager.h?p2=llvm/trunk/tools/lli/RemoteMemoryManager.h&p1=llvm/trunk/tools/lli/RecordingMemoryManager.h&r1=191860&r2=191938&rev=191938&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/tools/lli/RecordingMemoryManager.h (original)<br>
+++ llvm/trunk/tools/lli/RemoteMemoryManager.h Thu Oct  3 19:49:38 2013<br>
@@ -1,4 +1,4 @@<br>
-//===- RecordingMemoryManager.h - LLI MCJIT recording memory manager ------===//<br>
+//===- RemoteMemoryManager.h - LLI MCJIT recording memory manager ------===//<br>
 //<br>
 //                     The LLVM Compiler Infrastructure<br>
 //<br>
@@ -12,24 +12,47 @@<br>
 //<br>
 //===----------------------------------------------------------------------===//<br>
<br>
-#ifndef RECORDINGMEMORYMANAGER_H<br>
-#define RECORDINGMEMORYMANAGER_H<br>
+#ifndef REMOTEMEMORYMANAGER_H<br>
+#define REMOTEMEMORYMANAGER_H<br>
<br>
+#include "llvm/ADT/DenseMap.h"<br>
 #include "llvm/ADT/SmallVector.h"<br>
 #include "llvm/ExecutionEngine/JITMemoryManager.h"<br>
 #include "llvm/Support/ErrorHandling.h"<br>
 #include "llvm/Support/Memory.h"<br>
 #include <utility><br>
<br>
+#include "RemoteTarget.h"<br>
+<br>
 namespace llvm {<br>
<br>
-class RecordingMemoryManager : public JITMemoryManager {<br>
+class RemoteMemoryManager : public JITMemoryManager {<br>
 public:<br>
-  typedef std::pair<sys::MemoryBlock, unsigned> Allocation;<br>
+  // Notice that this structure takes ownership of the memory allocated.<br>
+  struct Allocation {<br>
+    Allocation(sys::MemoryBlock mb, unsigned a, bool code)<br>
+      : MB(mb), Alignment(a), IsCode(code) {}<br>
+<br>
+    sys::MemoryBlock  MB;<br>
+    unsigned          Alignment;<br>
+    bool              IsCode;<br>
+  };<br>
<br>
 private:<br>
-  SmallVector<Allocation, 16> AllocatedDataMem;<br>
-  SmallVector<Allocation, 16> AllocatedCodeMem;<br>
+  // This vector contains Allocation objects for all sections which we have<br>
+  // allocated.  This vector effectively owns the memory associated with the<br>
+  // allocations.<br>
+  SmallVector<Allocation, 2>  AllocatedSections;<br>
+<br>
+  // This vector contains pointers to Allocation objects for any sections we<br>
+  // have allocated locally but have not yet remapped for the remote target.<br>
+  // When we receive notification of a completed module load, we will map<br>
+  // these sections into the remote target.<br>
+  SmallVector<const Allocation *, 2>  UnmappedSections;<br>
+<br>
+  // This map tracks the sections we have remapped for the remote target<br>
+  // but have not yet copied to the target.<br>
+  DenseMap<uint64_t, const Allocation *>  MappedSections;<br>
<br>
   // FIXME: This is part of a work around to keep sections near one another<br>
   // when MCJIT performs relocations after code emission but before<br>
@@ -37,17 +60,11 @@ private:<br>
   sys::MemoryBlock Near;<br>
   sys::MemoryBlock allocateSection(uintptr_t Size);<br>
<br>
-public:<br>
-  RecordingMemoryManager() {}<br>
-  virtual ~RecordingMemoryManager();<br>
-<br>
-  typedef SmallVectorImpl<Allocation>::const_iterator const_data_iterator;<br>
-  typedef SmallVectorImpl<Allocation>::const_iterator const_code_iterator;<br>
+  RemoteTarget *Target;<br>
<br>
-  const_data_iterator data_begin() const { return AllocatedDataMem.begin(); }<br>
-  const_data_iterator   data_end() const { return AllocatedDataMem.end(); }<br>
-  const_code_iterator code_begin() const { return AllocatedCodeMem.begin(); }<br>
-  const_code_iterator   code_end() const { return AllocatedCodeMem.end(); }<br>
+public:<br>
+  RemoteMemoryManager() : Target(NULL) {}<br>
+  virtual ~RemoteMemoryManager();<br>
<br>
   uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,<br>
                                unsigned SectionID, StringRef SectionName);<br>
@@ -59,7 +76,12 @@ public:<br>
   void *getPointerToNamedFunction(const std::string &Name,<br>
                                   bool AbortOnFailure = true);<br>
<br>
-  bool finalizeMemory(std::string *ErrMsg) { return false; }<br>
+  void notifyObjectLoaded(ExecutionEngine *EE, const ObjectImage *Obj);<br>
+<br>
+  bool finalizeMemory(std::string *ErrMsg);<br>
+<br>
+  // This is a non-interface function used by lli<br>
+  void setRemoteTarget(RemoteTarget *T) { Target = T; }<br>
<br>
   // The following obsolete JITMemoryManager calls are stubbed out for<br>
   // this model.<br>
<br>
Modified: llvm/trunk/tools/lli/lli.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/lli.cpp?rev=191938&r1=191937&r2=191938&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/lli/lli.cpp?rev=191938&r1=191937&r2=191938&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/tools/lli/lli.cpp (original)<br>
+++ llvm/trunk/tools/lli/lli.cpp Thu Oct  3 19:49:38 2013<br>
@@ -15,7 +15,7 @@<br>
<br>
 #define DEBUG_TYPE "lli"<br>
 #include "llvm/IR/LLVMContext.h"<br>
-#include "RecordingMemoryManager.h"<br>
+#include "RemoteMemoryManager.h"<br>
 #include "RemoteTarget.h"<br>
 #include "llvm/ADT/Triple.h"<br>
 #include "llvm/Bitcode/ReaderWriter.h"<br>
@@ -131,6 +131,12 @@ namespace {<br>
             cl::value_desc("function"),<br>
             cl::init("main"));<br>
<br>
+  cl::list<std::string><br>
+  ExtraModules("extra-modules",<br>
+         cl::CommaSeparated,<br>
+         cl::desc("Extra modules to be loaded"),<br>
+         cl::value_desc("<input bitcode 2>,<input bitcode 3>,..."));<br>
+<br>
   cl::opt<std::string><br>
   FakeArgv0("fake-argv0",<br>
             cl::desc("Override the 'argv[0]' value passed into the executing"<br>
@@ -222,82 +228,6 @@ static void do_shutdown() {<br>
 #endif<br>
 }<br>
<br>
-void layoutRemoteTargetMemory(RemoteTarget *T, RecordingMemoryManager *JMM) {<br>
-  // Lay out our sections in order, with all the code sections first, then<br>
-  // all the data sections.<br>
-  uint64_t CurOffset = 0;<br>
-  unsigned MaxAlign = T->getPageAlignment();<br>
-  SmallVector<std::pair<const void*, uint64_t>, 16> Offsets;<br>
-  SmallVector<unsigned, 16> Sizes;<br>
-  for (RecordingMemoryManager::const_code_iterator I = JMM->code_begin(),<br>
-                                                   E = JMM->code_end();<br>
-       I != E; ++I) {<br>
-    DEBUG(dbgs() << "code region: size " << I->first.size()<br>
-                 << ", alignment " << I->second << "\n");<br>
-    // Align the current offset up to whatever is needed for the next<br>
-    // section.<br>
-    unsigned Align = I->second;<br>
-    CurOffset = (CurOffset + Align - 1) / Align * Align;<br>
-    // Save off the address of the new section and allocate its space.<br>
-    Offsets.push_back(std::pair<const void*,uint64_t>(I->first.base(), CurOffset));<br>
-    Sizes.push_back(I->first.size());<br>
-    CurOffset += I->first.size();<br>
-  }<br>
-  // Adjust to keep code and data aligned on seperate pages.<br>
-  CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign;<br>
-  unsigned FirstDataIndex = Offsets.size();<br>
-  for (RecordingMemoryManager::const_data_iterator I = JMM->data_begin(),<br>
-                                                   E = JMM->data_end();<br>
-       I != E; ++I) {<br>
-    DEBUG(dbgs() << "data region: size " << I->first.size()<br>
-                 << ", alignment " << I->second << "\n");<br>
-    // Align the current offset up to whatever is needed for the next<br>
-    // section.<br>
-    unsigned Align = I->second;<br>
-    CurOffset = (CurOffset + Align - 1) / Align * Align;<br>
-    // Save off the address of the new section and allocate its space.<br>
-    Offsets.push_back(std::pair<const void*,uint64_t>(I->first.base(), CurOffset));<br>
-    Sizes.push_back(I->first.size());<br>
-    CurOffset += I->first.size();<br>
-  }<br>
-<br>
-  // Allocate space in the remote target.<br>
-  uint64_t RemoteAddr;<br>
-  if (T->allocateSpace(CurOffset, MaxAlign, RemoteAddr))<br>
-    report_fatal_error(T->getErrorMsg());<br>
-  // Map the section addresses so relocations will get updated in the local<br>
-  // copies of the sections.<br>
-  for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {<br>
-    uint64_t Addr = RemoteAddr + Offsets[i].second;<br>
-    EE->mapSectionAddress(const_cast<void*>(Offsets[i].first), Addr);<br>
-<br>
-    DEBUG(dbgs() << "  Mapping local: " << Offsets[i].first<br>
-                 << " to remote: 0x" << format("%llx", Addr) << "\n");<br>
-<br>
-  }<br>
-<br>
-  // Trigger application of relocations<br>
-  EE->finalizeObject();<br>
-<br>
-  // Now load it all to the target.<br>
-  for (unsigned i = 0, e = Offsets.size(); i != e; ++i) {<br>
-    uint64_t Addr = RemoteAddr + Offsets[i].second;<br>
-<br>
-    if (i < FirstDataIndex) {<br>
-      T->loadCode(Addr, Offsets[i].first, Sizes[i]);<br>
-<br>
-      DEBUG(dbgs() << "  loading code: " << Offsets[i].first<br>
-            << " to remote: 0x" << format("%llx", Addr) << "\n");<br>
-    } else {<br>
-      T->loadData(Addr, Offsets[i].first, Sizes[i]);<br>
-<br>
-      DEBUG(dbgs() << "  loading data: " << Offsets[i].first<br>
-            << " to remote: 0x" << format("%llx", Addr) << "\n");<br>
-    }<br>
-<br>
-  }<br>
-}<br>
-<br>
 //===----------------------------------------------------------------------===//<br>
 // main Driver function<br>
 //<br>
@@ -370,7 +300,7 @@ int main(int argc, char **argv, char * c<br>
   if (UseMCJIT && !ForceInterpreter) {<br>
     builder.setUseMCJIT(true);<br>
     if (RemoteMCJIT)<br>
-      RTDyldMM = new RecordingMemoryManager();<br>
+      RTDyldMM = new RemoteMemoryManager();<br>
     else<br>
       RTDyldMM = new SectionMemoryManager();<br>
     builder.setMCJITMemoryManager(RTDyldMM);<br>
@@ -420,6 +350,16 @@ int main(int argc, char **argv, char * c<br>
     exit(1);<br>
   }<br>
<br>
+  // Load any additional modules specified on the command line.<br>
+  for (unsigned i = 0, e = ExtraModules.size(); i != e; ++i) {<br>
+    Module *XMod = ParseIRFile(ExtraModules[i], Err, Context);<br>
+    if (!XMod) {<br>
+      Err.print(argv[0], errs());<br>
+      return 1;<br>
+    }<br>
+    EE->addModule(XMod);<br>
+  }<br>
+<br>
   // The following functions have no effect if their respective profiling<br>
   // support wasn't enabled in the build configuration.<br>
   EE->RegisterJITEventListener(<br>
@@ -519,7 +459,7 @@ int main(int argc, char **argv, char * c<br>
     // it couldn't. This is a limitation of the LLI implemantation, not the<br>
     // MCJIT itself. FIXME.<br>
     //<br>
-    RecordingMemoryManager *MM = static_cast<RecordingMemoryManager*>(RTDyldMM);<br>
+    RemoteMemoryManager *MM = static_cast<RemoteMemoryManager*>(RTDyldMM);<br>
     // Everything is prepared now, so lay out our program for the target<br>
     // address space, assign the section addresses to resolve any relocations,<br>
     // and send it to the target.<br>
@@ -543,19 +483,30 @@ int main(int argc, char **argv, char * c<br>
       Target.reset(RemoteTarget::createRemoteTarget());<br>
     }<br>
<br>
-    // Create the remote target<br>
+    // Give the memory manager a pointer to our remote target interface object.<br>
+    MM->setRemoteTarget(Target.get());<br>
+<br>
+    // Create the remote target.<br>
     Target->create();<br>
<br>
+// FIXME: Don't commit like this.  I don't think these calls are necessary.<br></blockquote><div><br></div><div>!!!</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

+#if 0<br>
     // Trigger compilation.<br>
     EE->generateCodeForModule(Mod);<br>
<br>
-    // Layout the target memory.<br>
-    layoutRemoteTargetMemory(Target.get(), MM);<br>
+    // Get everything ready to execute.<br>
+    EE->finalizeModule(Mod);<br>
+#endif<br>
<br>
     // Since we're executing in a (at least simulated) remote address space,<br>
     // we can't use the ExecutionEngine::runFunctionAsMain(). We have to<br>
     // grab the function address directly here and tell the remote target<br>
     // to execute the function.<br>
+    //<br>
+    // Our memory manager will map generated code into the remote address<br>
+    // space as it is loaded and copy the bits over during the finalizeMemory<br>
+    // operation.<br>
+    //<br>
     // FIXME: argv and envp handling.<br>
     uint64_t Entry = EE->getFunctionAddress(EntryFn->getName().str());<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></div>