[Orc] Add lazy-JITting support for i386.

This patch adds a new class, OrcI386, which contains the hooks needed to
support lazy-JITing on i386 (currently only for Pentium 2 or above, as the JIT
re-entry code uses the FXSAVE/FXRSTOR instructions).

Support for i386 is enabled in the LLI lazy JIT and the Orc C API, and
regression and unit tests are enabled for this architecture.

llvm-svn: 260338
diff --git a/llvm/lib/ExecutionEngine/Orc/OrcArchitectureSupport.cpp b/llvm/lib/ExecutionEngine/Orc/OrcArchitectureSupport.cpp
index 606b561..c9b7311 100644
--- a/llvm/lib/ExecutionEngine/Orc/OrcArchitectureSupport.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/OrcArchitectureSupport.cpp
@@ -165,5 +165,130 @@
   return std::error_code();
 }
 
+void OrcI386::writeResolverCode(uint8_t *ResolverMem, JITReentryFn ReentryFn,
+                                void *CallbackMgr) {
+
+  const uint8_t ResolverCode[] = {
+                                              // resolver_entry:
+    0x55,                                     // 0x00: pushl    %ebp
+    0x89, 0xe5,                               // 0x01: movl     %esp, %ebp
+    0x50,                                     // 0x03: pushl    %eax
+    0x53,                                     // 0x04: pushl    %ebx
+    0x51,                                     // 0x05: pushl    %ecx
+    0x52,                                     // 0x06: pushl    %edx
+    0x56,                                     // 0x07: pushl    %esi
+    0x57,                                     // 0x08: pushl    %edi
+    0x81, 0xec, 0x1C, 0x02, 0x00, 0x00,       // 0x09: subl     $0x21C, %esp
+    0x0f, 0xae, 0x44, 0x24, 0x10,             // 0x0f: fxsave   0x10(%esp)
+    0x8b, 0x75, 0x04,                         // 0x14: movl     0x4(%ebp), %esi
+    0x83, 0xee, 0x05,                         // 0x17: subl     $0x5, %esi
+    0x89, 0x74, 0x24, 0x04,                   // 0x1a: movl     %esi, 0x4(%esp)
+    0xc7, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00, // 0x1e: movl     <cbmgr>, (%esp)
+    0xb8, 0x00, 0x00, 0x00, 0x00,             // 0x25: movl     <reentry>, %eax
+    0xff, 0xd0,                               // 0x2a: calll    *%eax
+    0x89, 0x45, 0x04,                         // 0x2c: movl     %eax, 0x4(%ebp)
+    0x0f, 0xae, 0x4c, 0x24, 0x10,             // 0x2f: fxrstor  0x10(%esp)
+    0x81, 0xc4, 0x1c, 0x02, 0x00, 0x00,       // 0x34: addl     $0x21C, %esp
+    0x5f,                                     // 0x3a: popl     %edi
+    0x5e,                                     // 0x3b: popl     %esi
+    0x5a,                                     // 0x3c: popl     %edx
+    0x59,                                     // 0x3d: popl     %ecx
+    0x5b,                                     // 0x3e: popl     %ebx
+    0x58,                                     // 0x3f: popl     %eax
+    0x5d,                                     // 0x40: popl     %ebp
+    0xc3                                      // 0x41: retl
+  };
+
+  const unsigned ReentryFnAddrOffset = 0x26;
+  const unsigned CallbackMgrAddrOffset = 0x21;
+
+  memcpy(ResolverMem, ResolverCode, sizeof(ResolverCode));
+  memcpy(ResolverMem + ReentryFnAddrOffset, &ReentryFn, sizeof(ReentryFn));
+  memcpy(ResolverMem + CallbackMgrAddrOffset, &CallbackMgr,
+         sizeof(CallbackMgr));
+}
+
+void OrcI386::writeTrampolines(uint8_t *TrampolineMem, void *ResolverAddr,
+                               unsigned NumTrampolines) {
+
+  uint64_t CallRelImm = 0xF1C4C400000000e8;
+  uint64_t Resolver = reinterpret_cast<uint64_t>(ResolverAddr);
+  uint64_t ResolverRel =
+    Resolver - reinterpret_cast<uint64_t>(TrampolineMem) - 5;
+
+  uint64_t *Trampolines = reinterpret_cast<uint64_t*>(TrampolineMem);
+  for (unsigned I = 0; I < NumTrampolines; ++I, ResolverRel -= TrampolineSize)
+    Trampolines[I] = CallRelImm | (ResolverRel << 8);
+}
+
+std::error_code OrcI386::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
+                                                unsigned MinStubs,
+                                                void *InitialPtrVal) {
+  // Stub format is:
+  //
+  // .section __orc_stubs
+  // stub1:
+  //                 jmpq    *ptr1
+  //                 .byte   0xC4         ; <- Invalid opcode padding.
+  //                 .byte   0xF1
+  // stub2:
+  //                 jmpq    *ptr2
+  //
+  // ...
+  //
+  // .section __orc_ptrs
+  // ptr1:
+  //                 .quad 0x0
+  // ptr2:
+  //                 .quad 0x0
+  //
+  // ...
+
+  const unsigned StubSize = IndirectStubsInfo::StubSize;
+
+  // Emit at least MinStubs, rounded up to fill the pages allocated.
+  unsigned PageSize = sys::Process::getPageSize();
+  unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
+  unsigned NumStubs = (NumPages * PageSize) / StubSize;
+
+  // Allocate memory for stubs and pointers in one call.
+  std::error_code EC;
+  auto StubsMem =
+    sys::OwningMemoryBlock(
+      sys::Memory::allocateMappedMemory(2 * NumPages * PageSize, nullptr,
+                                        sys::Memory::MF_READ |
+                                        sys::Memory::MF_WRITE,
+                                        EC));
+
+  if (EC)
+    return EC;
+
+  // Create separate MemoryBlocks representing the stubs and pointers.
+  sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
+  sys::MemoryBlock PtrsBlock(static_cast<char*>(StubsMem.base()) +
+                               NumPages * PageSize,
+                             NumPages * PageSize);
+
+  // Populate the stubs page stubs and mark it executable.
+  uint64_t *Stub = reinterpret_cast<uint64_t*>(StubsBlock.base());
+  uint64_t PtrAddr = reinterpret_cast<uint64_t>(PtrsBlock.base());
+  for (unsigned I = 0; I < NumStubs; ++I, PtrAddr += 4)
+    Stub[I] = 0xF1C40000000025ff | (PtrAddr << 16);
+
+  if (auto EC = sys::Memory::protectMappedMemory(StubsBlock,
+                                                 sys::Memory::MF_READ |
+                                                 sys::Memory::MF_EXEC))
+    return EC;
+
+  // Initialize all pointers to point at FailureAddress.
+  void **Ptr = reinterpret_cast<void**>(PtrsBlock.base());
+  for (unsigned I = 0; I < NumStubs; ++I)
+    Ptr[I] = InitialPtrVal;
+
+  StubsInfo = IndirectStubsInfo(NumStubs, std::move(StubsMem));
+
+  return std::error_code();
+}
+
 } // End namespace orc.
 } // End namespace llvm.
diff --git a/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.cpp b/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.cpp
index 956daae..412e605 100644
--- a/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.cpp
@@ -22,6 +22,11 @@
   switch (T.getArch()) {
     default: return nullptr;
 
+    case Triple::x86: {
+      typedef orc::LocalJITCompileCallbackManager<orc::OrcI386> CCMgrT;
+      return llvm::make_unique<CCMgrT>(0);
+    };
+
     case Triple::x86_64: {
       typedef orc::LocalJITCompileCallbackManager<orc::OrcX86_64> CCMgrT;
       return llvm::make_unique<CCMgrT>(0);
@@ -34,6 +39,12 @@
   switch (T.getArch()) {
     default: return nullptr;
 
+    case Triple::x86:
+      return [](){
+        return llvm::make_unique<
+                 orc::LocalIndirectStubsManager<orc::OrcI386>>();
+      };
+
     case Triple::x86_64:
       return [](){
         return llvm::make_unique<