[llvm-commits] CVS: llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp

Misha Brukman brukman at cs.uiuc.edu
Fri Sep 5 18:00:01 PDT 2003


Changes in directory llvm/lib/Target/Sparc:

SparcV9CodeEmitter.cpp updated: 1.31 -> 1.32

---
Log message:

Added some optimizations:
* Generate a single BA instead of 6-instruction JUMP if possible
  (this occurs both in the creation and overwriting of the stub code)
* If possible, rewrite the ORIGINAL call to call the generated function
  directly, thus bypassing the stub entirely

Also added some statistics on how often calls are overwritten and how often the
CompilationCallback is invoked.


---
Diffs of the changes:

Index: llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp
diff -u llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp:1.31 llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp:1.32
--- llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp:1.31	Thu Aug 28 23:22:54 2003
+++ llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp	Fri Sep  5 17:59:31 2003
@@ -17,10 +17,17 @@
 #include "llvm/Target/TargetData.h"
 #include "Support/Debug.h"
 #include "Support/hash_set"
+#include "Support/Statistic.h"
 #include "SparcInternals.h"
 #include "SparcV9CodeEmitter.h"
 #include "Config/alloca.h"
 
+namespace {
+  Statistic<> OverwrittenCalls("call-ovwr", "Number of over-written calls");
+  Statistic<> UnmodifiedCalls("call-skip", "Number of unmodified calls");
+  Statistic<> CallbackCalls("callback", "Number CompilationCallback() calls");
+}
+
 bool UltraSparc::addPassesToEmitMachineCode(FunctionPassManager &PM,
                                             MachineCodeEmitter &MCE) {
   MachineCodeEmitter *M = &MCE;
@@ -76,8 +83,10 @@
 
   private:
     uint64_t emitStubForFunction(Function *F);
-    static void SaveRegisters(uint64_t DoubleFP[]);
-    static void RestoreRegisters(uint64_t DoubleFP[]);
+    static void SaveRegisters(uint64_t DoubleFP[], uint64_t &FSR,
+                              uint64_t &FPRS, uint64_t &CCR);
+    static void RestoreRegisters(uint64_t DoubleFP[], uint64_t &FSR,
+                                 uint64_t &FPRS, uint64_t &CCR);
     static void CompilationCallback();
     uint64_t resolveFunctionReference(uint64_t RetAddr);
 
@@ -164,7 +173,8 @@
   return Addr;
 }
 
-void JITResolver::SaveRegisters(uint64_t DoubleFP[]) {
+void JITResolver::SaveRegisters(uint64_t DoubleFP[], uint64_t &FSR, 
+                                uint64_t &FPRS, uint64_t &CCR) {
 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
 
 #if 0
@@ -215,7 +225,9 @@
 }
 
 
-void JITResolver::RestoreRegisters(uint64_t DoubleFP[]) {
+void JITResolver::RestoreRegisters(uint64_t DoubleFP[], uint64_t &FSR, 
+                                   uint64_t &FPRS, uint64_t &CCR)
+{
 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
 
 #if 0
@@ -268,11 +280,13 @@
 void JITResolver::CompilationCallback() {
   // Local space to save double registers
   uint64_t DoubleFP[32];
-  //uint64_t CCR, FSR, FPRS;
+  uint64_t FSR, FPRS, CCR;
 
-  SaveRegisters(DoubleFP);
+  SaveRegisters(DoubleFP, FSR, FPRS, CCR);
+  ++CallbackCalls;
 
   uint64_t CameFrom = (uint64_t)(intptr_t)__builtin_return_address(0);
+  uint64_t CameFrom1 = (uint64_t)(intptr_t)__builtin_return_address(1);
   int64_t Target = (int64_t)TheJITResolver->resolveFunctionReference(CameFrom);
   DEBUG(std::cerr << "In callback! Addr=0x" << std::hex << CameFrom << "\n");
   register int64_t returnAddr = 0;
@@ -283,6 +297,23 @@
                   << std::hex << *(unsigned*)returnAddr << "\n");
 #endif
 
+  // If we can rewrite the ORIGINAL caller, we eliminate the whole need for a
+  // trampoline function stub!!
+  unsigned OrigCallInst = *((unsigned*)(intptr_t)CameFrom1);
+  int64_t OrigTarget = (Target-CameFrom1) >> 2;
+  if ((OrigCallInst & (1 << 30)) && 
+      (OrigTarget <= (1 << 30) && OrigTarget >= -(1 << 30)))
+  {
+    // The original call instruction was CALL <immed>, which means we can
+    // overwrite it directly, since the offset will fit into 30 bits
+    MachineInstr *C = BuildMI(V9::CALL, 1).addSImm(OrigTarget);
+    *((unsigned*)(intptr_t)CameFrom1)=TheJITResolver->getBinaryCodeForInstr(*C);
+    delete C;
+    ++OverwrittenCalls;
+  } else {
+    ++UnmodifiedCalls;
+  }
+
   // Rewrite the call target so that we don't fault every time we execute it.
   //
 
@@ -296,13 +327,13 @@
 
   // FIXME FIXME FIXME FIXME: __builtin_frame_address doesn't work if frame
   // pointer elimination has been performed.  Having a variable sized alloca
-  // disables frame pointer elimination currently, even if it's dead.  This is a
-  // gross hack.
+  // disables frame pointer elimination currently, even if it's dead.  This is
+  // a gross hack.
   alloca(42+Offset);
   // FIXME FIXME FIXME FIXME
   
   // Make sure that what we're about to overwrite is indeed "save"
-  MachineInstr *SV = BuildMI(V9::SAVEi, 3).addReg(o6).addSImm(-192).addReg(o6);
+  MachineInstr *SV =BuildMI(V9::SAVEi, 3).addReg(o6).addSImm(-192).addReg(o6);
   unsigned SaveInst = TheJITResolver->getBinaryCodeForInstr(*SV);
   delete SV;
   unsigned CodeInMem = *(unsigned*)(intptr_t)CodeBegin;
@@ -310,32 +341,35 @@
     std::cerr << "About to overwrite smthg not a save instr!";
     abort();
   }
-  DEBUG(std::cerr << "Emitting a far jump to 0x" << std::hex << Target << "\n");
-  TheJITResolver->insertFarJumpAtAddr(Target, CodeBegin);
+  DEBUG(std::cerr << "Emitting a jump to 0x" << std::hex << Target << "\n");
 
-  // FIXME: if the target function is close enough to fit into the 19bit disp of
+  // If the target function is close enough to fit into the 19bit disp of
   // BA, we should use this version, as its much cheaper to generate.
-#if 0  
-  uint64_t InstAddr = CodeBegin;
-  // ba <target>
-  MachineInstr *MI = BuildMI(V9::BA, 1).addSImm(Target);
-  *((unsigned*)(intptr_t)InstAddr)=TheJITResolver->getBinaryCodeForInstr(*MI);
-  InstAddr += 4;
-  delete MI;
-
-  // nop
-  MI = BuildMI(V9::NOP, 0);
-  *((unsigned*)(intptr_t))=TheJITResolver->getBinaryCodeForInstr(*Nop);
-  delete MI;
-#endif
+  int64_t BranchTarget = (Target-CodeBegin) >> 2;
+  if (BranchTarget >= (1 << 19) || BranchTarget <= -(1 << 19)) {
+    TheJITResolver->insertFarJumpAtAddr(Target, CodeBegin);
+  } else {
+    // ba <target>
+    MachineInstr *I = BuildMI(V9::BA, 1).addSImm(BranchTarget);
+    *((unsigned*)(intptr_t)CodeBegin) = 
+      TheJITResolver->getBinaryCodeForInstr(*I);
+    CodeBegin += 4;
+    delete I;
+
+    // nop
+    I = BuildMI(V9::NOP, 0);
+    *((unsigned*)(intptr_t)CodeBegin) = 
+      TheJITResolver->getBinaryCodeForInstr(*I);
+    delete I;
+  }
 
-  RestoreRegisters(DoubleFP);
+  RestoreRegisters(DoubleFP, FSR, FPRS, CCR);
 
-  // Change the return address to reexecute the restore, then the jump However,
+  // Change the return address to reexecute the restore, then the jump. However,
   // we can't just modify %i7 here, because we return to the function that will
   // restore the floating-point registers for us. Thus, we just return the value
   // we want it to be, and the parent will take care of setting %i7 correctly.
-  DEBUG(std::cerr << "Callback returning the addr of restore inst: "
+  DEBUG(std::cerr << "Callback returning to: 0x"
                   << std::hex << (CameFrom-Offset-12) << "\n");
 #if defined(sparc) || defined(__sparc__) || defined(__sparcv9)
   __asm__ __volatile__ ("sub %%i7, %0, %%i7" : : "r" (Offset+12));
@@ -370,13 +404,12 @@
   int64_t CurrPC = MCE.getCurrentPCValue();
   int64_t Addr = (int64_t)addFunctionReference(CurrPC, F);
   int64_t CallTarget = (Addr-CurrPC) >> 2;
-  //if (CallTarget >= (1 << 29) || CallTarget <= -(1 << 29)) {
-  // Since this is a far call, the actual address of the call is shifted
-  // by the number of instructions it takes to calculate the exact address
+  if (CallTarget >= (1 << 29) || CallTarget <= -(1 << 29)) {
+    // Since this is a far call, the actual address of the call is shifted
+    // by the number of instructions it takes to calculate the exact address
     deleteFunctionReference(CurrPC);
     SparcV9.emitFarCall(Addr, F);
-#if 0
-  else {
+  } else {
     // call CallTarget              ;; invoke the callback
     MachineInstr *Call = BuildMI(V9::CALL, 1).addSImm(CallTarget);
     SparcV9.emitWord(SparcV9.getBinaryCodeForInstr(*Call));
@@ -389,7 +422,6 @@
 
     addCallFlavor(CurrPC, ShortCall);
   }
-#endif
 
   SparcV9.emitWord(0xDEADBEEF); // marker so that we know it's really a stub
   return (intptr_t)MCE.finishFunctionStub(*F)+4; /* 1 instr past the restore */





More information about the llvm-commits mailing list