I swear I did a make clean and make before committing all this...
[oota-llvm.git] / lib / Target / PowerPC / PPCJITInfo.cpp
index 6dea3d3306b6c4a13244b5bdb102d2718d4b3420..78383e0603bdacfc02d988f6d5e34c47ff9f8d8c 100644 (file)
 #include "PPCJITInfo.h"
 #include "PPCRelocations.h"
 #include "PPCTargetMachine.h"
-#include "llvm/CodeGen/MachineCodeEmitter.h"
-#include "llvm/Config/alloca.h"
+#include "llvm/Function.h"
+#include "llvm/Support/Memory.h"
 #include "llvm/Support/Debug.h"
-#include <set>
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
 using namespace llvm;
 
 static TargetJITInfo::JITCompilerFn JITCompilerFunction;
@@ -71,7 +72,7 @@ extern "C" void PPC32CompilationCallback();
 extern "C" void PPC64CompilationCallback();
 
 #if (defined(__POWERPC__) || defined (__ppc__) || defined(_POWER)) && \
-    !defined(__ppc64__)
+    !(defined(__ppc64__) || defined(__FreeBSD__))
 // CompilationCallback stub - We can't use a C function with inline assembly in
 // it, because we the prolog/epilog inserted by GCC won't work for us.  Instead,
 // write our own wrapper, which does things our way, so we have complete control
@@ -137,7 +138,7 @@ asm(
     );
 
 #elif defined(__PPC__) && !defined(__ppc64__)
-// Linux/PPC support
+// Linux & FreeBSD / PPC 32 support
 
 // CompilationCallback stub - We can't use a C function with inline assembly in
 // it, because we the prolog/epilog inserted by GCC won't work for us.  Instead,
@@ -198,8 +199,7 @@ asm(
     );
 #else
 void PPC32CompilationCallback() {
-  assert(0 && "This is not a power pc, you can't execute this!");
-  abort();
+  llvm_unreachable("This is not a power pc, you can't execute this!");
 }
 #endif
 
@@ -265,8 +265,7 @@ asm(
     );
 #else
 void PPC64CompilationCallback() {
-  assert(0 && "This is not a power pc, you can't execute this!");
-  abort();
+  llvm_unreachable("This is not a power pc, you can't execute this!");
 }
 #endif
 
@@ -309,6 +308,7 @@ extern "C" void *PPCCompilationCallbackC(unsigned *StubCallAddrPlus4,
   // Rewrite the stub with an unconditional branch to the target, for any users
   // who took the address of the stub.
   EmitBranchToAt((intptr_t)StubCallAddr, (intptr_t)Target, false, is64Bit);
+  sys::Memory::InvalidateInstructionCache(StubCallAddr, 7*4);
 
   // Put the address of the target function to call and the address to return to
   // after calling the target function in a place that is easy to get on the
@@ -324,65 +324,64 @@ PPCJITInfo::getLazyResolverFunction(JITCompilerFn Fn) {
   return is64Bit ? PPC64CompilationCallback : PPC32CompilationCallback;
 }
 
-#if (defined(__POWERPC__) || defined (__ppc__) || defined(_POWER)) && \
-defined(__APPLE__)
-extern "C" void sys_icache_invalidate(const void *Addr, size_t len);
-#endif
+TargetJITInfo::StubLayout PPCJITInfo::getStubLayout() {
+  // The stub contains up to 10 4-byte instructions, aligned at 4 bytes: 3
+  // instructions to save the caller's address if this is a lazy-compilation
+  // stub, plus a 1-, 4-, or 7-instruction sequence to load an arbitrary address
+  // into a register and jump through it.
+  StubLayout Result = {10*4, 4};
+  return Result;
+}
 
-/// SyncICache - On PPC, the JIT emitted code must be explicitly refetched to
-/// ensure correct execution.
-static void SyncICache(const void *Addr, size_t len) {
 #if (defined(__POWERPC__) || defined (__ppc__) || defined(_POWER)) && \
 defined(__APPLE__)
-  sys_icache_invalidate(Addr, len);
+extern "C" void sys_icache_invalidate(const void *Addr, size_t len);
 #endif
-}
 
-void *PPCJITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) {
+void *PPCJITInfo::emitFunctionStub(const Function* F, void *Fn,
+                                   JITCodeEmitter &JCE) {
   // If this is just a call to an external function, emit a branch instead of a
   // call.  The code is the same except for one bit of the last instruction.
   if (Fn != (void*)(intptr_t)PPC32CompilationCallback && 
       Fn != (void*)(intptr_t)PPC64CompilationCallback) {
-    MCE.startFunctionStub(7*4);
-    intptr_t Addr = (intptr_t)MCE.getCurrentPCValue();
-    MCE.emitWordBE(0);
-    MCE.emitWordBE(0);
-    MCE.emitWordBE(0);
-    MCE.emitWordBE(0);
-    MCE.emitWordBE(0);
-    MCE.emitWordBE(0);
-    MCE.emitWordBE(0);
-    EmitBranchToAt(Addr, (intptr_t)Fn, false, is64Bit);
-    SyncICache((void*)Addr, 7*4);
-    return MCE.finishFunctionStub(0);
+    void *Addr = (void*)JCE.getCurrentPCValue();
+    JCE.emitWordBE(0);
+    JCE.emitWordBE(0);
+    JCE.emitWordBE(0);
+    JCE.emitWordBE(0);
+    JCE.emitWordBE(0);
+    JCE.emitWordBE(0);
+    JCE.emitWordBE(0);
+    EmitBranchToAt((intptr_t)Addr, (intptr_t)Fn, false, is64Bit);
+    sys::Memory::InvalidateInstructionCache(Addr, 7*4);
+    return Addr;
   }
 
-  MCE.startFunctionStub(10*4);
-  intptr_t Addr = (intptr_t)MCE.getCurrentPCValue();
+  void *Addr = (void*)JCE.getCurrentPCValue();
   if (is64Bit) {
-    MCE.emitWordBE(0xf821ffb1);     // stdu r1,-80(r1)
-    MCE.emitWordBE(0x7d6802a6);     // mflr r11
-    MCE.emitWordBE(0xf9610060);     // std r11, 96(r1)
-  } else if (TM.getSubtargetImpl()->isMachoABI()){
-    MCE.emitWordBE(0x9421ffe0);     // stwu r1,-32(r1)
-    MCE.emitWordBE(0x7d6802a6);     // mflr r11
-    MCE.emitWordBE(0x91610028);     // stw r11, 40(r1)
+    JCE.emitWordBE(0xf821ffb1);     // stdu r1,-80(r1)
+    JCE.emitWordBE(0x7d6802a6);     // mflr r11
+    JCE.emitWordBE(0xf9610060);     // std r11, 96(r1)
+  } else if (TM.getSubtargetImpl()->isDarwinABI()){
+    JCE.emitWordBE(0x9421ffe0);     // stwu r1,-32(r1)
+    JCE.emitWordBE(0x7d6802a6);     // mflr r11
+    JCE.emitWordBE(0x91610028);     // stw r11, 40(r1)
   } else {
-    MCE.emitWordBE(0x9421ffe0);     // stwu r1,-32(r1)
-    MCE.emitWordBE(0x7d6802a6);     // mflr r11
-    MCE.emitWordBE(0x91610024);     // stw r11, 36(r1)
+    JCE.emitWordBE(0x9421ffe0);     // stwu r1,-32(r1)
+    JCE.emitWordBE(0x7d6802a6);     // mflr r11
+    JCE.emitWordBE(0x91610024);     // stw r11, 36(r1)
   }
-  intptr_t BranchAddr = (intptr_t)MCE.getCurrentPCValue();
-  MCE.emitWordBE(0);
-  MCE.emitWordBE(0);
-  MCE.emitWordBE(0);
-  MCE.emitWordBE(0);
-  MCE.emitWordBE(0);
-  MCE.emitWordBE(0);
-  MCE.emitWordBE(0);
+  intptr_t BranchAddr = (intptr_t)JCE.getCurrentPCValue();
+  JCE.emitWordBE(0);
+  JCE.emitWordBE(0);
+  JCE.emitWordBE(0);
+  JCE.emitWordBE(0);
+  JCE.emitWordBE(0);
+  JCE.emitWordBE(0);
+  JCE.emitWordBE(0);
   EmitBranchToAt(BranchAddr, (intptr_t)Fn, true, is64Bit);
-  SyncICache((void*)Addr, 10*4);
-  return MCE.finishFunctionStub(0);
+  sys::Memory::InvalidateInstructionCache(Addr, 10*4);
+  return Addr;
 }
 
 
@@ -392,7 +391,7 @@ void PPCJITInfo::relocate(void *Function, MachineRelocation *MR,
     unsigned *RelocPos = (unsigned*)Function + MR->getMachineCodeOffset()/4;
     intptr_t ResultPtr = (intptr_t)MR->getResultPointer();
     switch ((PPC::RelocationType)MR->getRelocationType()) {
-    default: assert(0 && "Unknown relocation type!");
+    default: llvm_unreachable("Unknown relocation type!");
     case PPC::reloc_pcrel_bx:
       // PC-relative relocation for b and bl instructions.
       ResultPtr = (ResultPtr-(intptr_t)RelocPos) >> 2;
@@ -443,4 +442,5 @@ void PPCJITInfo::relocate(void *Function, MachineRelocation *MR,
 
 void PPCJITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
   EmitBranchToAt((intptr_t)Old, (intptr_t)New, false, is64Bit);
+  sys::Memory::InvalidateInstructionCache(Old, 7*4);
 }