[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