summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMisha Brukman <brukman+llvm@gmail.com>2003-07-15 19:09:43 +0000
committerMisha Brukman <brukman+llvm@gmail.com>2003-07-15 19:09:43 +0000
commit07d4516f92e866ec7900146789333a819f4f06df (patch)
tree3a201e74ea63aff300576326eb7e4e593c16524d /lib
parent859e09f06ea44b9182119fce4c75ba52baf429a6 (diff)
downloadllvm-07d4516f92e866ec7900146789333a819f4f06df.tar.gz
llvm-07d4516f92e866ec7900146789333a819f4f06df.tar.bz2
llvm-07d4516f92e866ec7900146789333a819f4f06df.tar.xz
Correctly handle calls to functions which are further away than 2**32 bits will
allow, i.e. make a sequence of instructions to enable an indirect call using jump-and-link and 2 temporary registers (which we save and ultimately restore). Warning: if the delay slot of a function call is used to do meaningful work and not just a NOP, this behavior is incorrect. However, the Sparc backend does not yet utilize the delay slots effectively, so it is not necessary to make an overly complicated algorithm for something that's not used. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@7178 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/Target/SparcV9/SparcV9CodeEmitter.cpp101
-rw-r--r--lib/Target/SparcV9/SparcV9CodeEmitter.h2
2 files changed, 97 insertions, 6 deletions
diff --git a/lib/Target/SparcV9/SparcV9CodeEmitter.cpp b/lib/Target/SparcV9/SparcV9CodeEmitter.cpp
index 7a40a7aec1..bc638c337a 100644
--- a/lib/Target/SparcV9/SparcV9CodeEmitter.cpp
+++ b/lib/Target/SparcV9/SparcV9CodeEmitter.cpp
@@ -414,6 +414,79 @@ SparcV9CodeEmitter::getRealRegNum(unsigned fakeReg,
}
+// WARNING: if the call used the delay slot to do meaningful work, that's not
+// being accounted for, and the behavior will be incorrect!!
+inline void SparcV9CodeEmitter::emitFarCall(uint64_t Target) {
+ static const unsigned i1 = SparcIntRegClass::i1, i2 = SparcIntRegClass::i2,
+ i7 = SparcIntRegClass::i7,
+ o6 = SparcIntRegClass::o6, g0 = SparcIntRegClass::g0;
+
+ //
+ // Save %i1, %i2 to the stack so we can form a 64-bit constant in %i2
+ //
+
+ // stx %i1, [%sp + 2119] ;; save %i1 to the stack, used as temp
+ MachineInstr *STX = BuildMI(V9::STXi, 3).addReg(i1).addReg(o6).addSImm(2119);
+ emitWord(getBinaryCodeForInstr(*STX));
+ delete STX;
+
+ // stx %i2, [%sp + 2127] ;; save %i2 to the stack
+ STX = BuildMI(V9::STXi, 3).addReg(i2).addReg(o6).addSImm(2127);
+ emitWord(getBinaryCodeForInstr(*STX));
+ delete STX;
+
+ //
+ // Get address to branch into %i2, using %i1 as a temporary
+ //
+
+ // sethi %uhi(Target), %i1 ;; get upper 22 bits of Target into %i1
+ MachineInstr *SH = BuildMI(V9::SETHI, 2).addSImm(Target >> 42).addReg(i1);
+ emitWord(getBinaryCodeForInstr(*SH));
+ delete SH;
+
+ // or %i1, %ulo(Target), %i1 ;; get 10 lower bits of upper word into %1
+ MachineInstr *OR = BuildMI(V9::ORi, 3)
+ .addReg(i1).addSImm((Target >> 32) & 0x03ff).addReg(i1);
+ emitWord(getBinaryCodeForInstr(*OR));
+ delete OR;
+
+ // sllx %i1, 32, %i1 ;; shift those 10 bits to the upper word
+ MachineInstr *SL = BuildMI(V9::SLLXi6, 3).addReg(i1).addSImm(32).addReg(i1);
+ emitWord(getBinaryCodeForInstr(*SL));
+ delete SL;
+
+ // sethi %hi(Target), %i2 ;; extract bits 10-31 into the dest reg
+ SH = BuildMI(V9::SETHI, 2).addSImm((Target >> 10) & 0x03fffff).addReg(i2);
+ emitWord(getBinaryCodeForInstr(*SH));
+ delete SH;
+
+ // or %i1, %i2, %i2 ;; get upper word (in %i1) into %i2
+ OR = BuildMI(V9::ORr, 3).addReg(i1).addReg(i2).addReg(i2);
+ emitWord(getBinaryCodeForInstr(*OR));
+ delete OR;
+
+ // or %i2, %lo(Target), %i2 ;; get lowest 10 bits of Target into %i2
+ OR = BuildMI(V9::ORi, 3).addReg(i2).addSImm(Target & 0x03ff).addReg(i2);
+ emitWord(getBinaryCodeForInstr(*OR));
+ delete OR;
+
+ // ldx [%sp + 2119], %i1 ;; restore %i1 -> 2119 = BIAS(2047) + 72
+ MachineInstr *LDX = BuildMI(V9::LDXi, 3).addReg(o6).addSImm(2119).addReg(i1);
+ emitWord(getBinaryCodeForInstr(*LDX));
+ delete LDX;
+
+ // jmpl %i2, %g0, %07 ;; indirect call on %i2
+ MachineInstr *J = BuildMI(V9::JMPLRETr, 3).addReg(i2).addReg(g0).addReg(07);
+ emitWord(getBinaryCodeForInstr(*J));
+ delete J;
+
+ // ldx [%sp + 2127], %i2 ;; restore %i2 -> 2127 = BIAS(2047) + 80
+ LDX = BuildMI(V9::LDXi, 3).addReg(o6).addSImm(2127).addReg(i2);
+ emitWord(getBinaryCodeForInstr(*LDX));
+ delete LDX;
+}
+
+
int64_t SparcV9CodeEmitter::getMachineOpValue(MachineInstr &MI,
MachineOperand &MO) {
int64_t rv = 0; // Return value; defaults to 0 for unhandled cases
@@ -479,10 +552,18 @@ int64_t SparcV9CodeEmitter::getMachineOpValue(MachineInstr &MI,
int64_t CurrPC = MCE.getCurrentPCValue();
DEBUG(std::cerr << "rv addr: 0x" << std::hex << rv << "\n"
<< "curr PC: 0x" << CurrPC << "\n");
- rv = (rv - CurrPC) >> 2;
- if (rv >= (1<<29) || rv <= -(1<<29)) {
- std::cerr << "addr out of bounds for the 30-bit call: " << rv << "\n";
- abort();
+ int64_t CallInstTarget = (rv - CurrPC) >> 2;
+ if (CallInstTarget >= (1<<29) || CallInstTarget <= -(1<<29)) {
+ DEBUG(std::cerr << "Making far call!\n");
+ // addresss is out of bounds for the 30-bit call,
+ // make an indirect jump-and-link
+ emitFarCall(rv);
+ // this invalidates the instruction so that the call with an incorrect
+ // address will not be emitted
+ rv = 0;
+ } else {
+ // The call fits into 30 bits, so just return the corrected address
+ rv = CallInstTarget;
}
DEBUG(std::cerr << "returning addr: 0x" << rv << "\n");
}
@@ -627,8 +708,16 @@ bool SparcV9CodeEmitter::runOnMachineFunction(MachineFunction &MF) {
void SparcV9CodeEmitter::emitBasicBlock(MachineBasicBlock &MBB) {
currBB = MBB.getBasicBlock();
BBLocations[currBB] = MCE.getCurrentPCValue();
- for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I)
- emitWord(getBinaryCodeForInstr(**I));
+ for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I){
+ unsigned binCode = getBinaryCodeForInstr(**I);
+ if (binCode == (1 << 30)) {
+ // this is an invalid call: the addr is out of bounds. that means a code
+ // sequence has already been emitted, and this is a no-op
+ DEBUG(std::cerr << "Call supressed: already emitted far call.\n");
+ } else {
+ emitWord(binCode);
+ }
+ }
}
void* SparcV9CodeEmitter::getGlobalAddress(GlobalValue *V, MachineInstr &MI,
diff --git a/lib/Target/SparcV9/SparcV9CodeEmitter.h b/lib/Target/SparcV9/SparcV9CodeEmitter.h
index 86f74c14c8..ca365d0684 100644
--- a/lib/Target/SparcV9/SparcV9CodeEmitter.h
+++ b/lib/Target/SparcV9/SparcV9CodeEmitter.h
@@ -49,6 +49,8 @@ private:
bool isPCRelative);
bool isFPInstr(MachineInstr &MI);
unsigned getRealRegNum(unsigned fakeReg, MachineInstr &MI);
+ inline void emitFarCall(uint64_t Addr);
+
};
#endif