diff options
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp | 250 | ||||
| -rw-r--r-- | llvm/lib/Target/Sparc/SparcV9CodeEmitter.h | 4 | 
2 files changed, 223 insertions, 31 deletions
| diff --git a/llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp b/llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp index 00a7e7c6268..3ec0656ab39 100644 --- a/llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp +++ b/llvm/lib/Target/Sparc/SparcV9CodeEmitter.cpp @@ -54,10 +54,13 @@ namespace {        return SparcV9.getBinaryCodeForInstr(MI);      } +    inline uint64_t insertFarJumpAtAddr(int64_t Value, uint64_t Addr); +    private:      uint64_t emitStubForFunction(Function *F);      static void CompilationCallback();      uint64_t resolveFunctionReference(uint64_t RetAddr); +    };    JITResolver *TheJITResolver; @@ -92,27 +95,175 @@ uint64_t JITResolver::getLazyResolver(Function *F) {    return Stub;  } -void JITResolver::CompilationCallback() { -  uint64_t *StackPtr = (uint64_t*)__builtin_frame_address(0); -  uint64_t RetAddr = (uint64_t)(intptr_t)__builtin_return_address(0); - -  std::cerr << "In callback! Addr=0x" << std::hex << RetAddr -            << " SP=0x" << (uint64_t)(intptr_t)StackPtr << std::dec << "\n"; +uint64_t JITResolver::insertFarJumpAtAddr(int64_t Target, uint64_t Addr) { + +  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); +  *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*STX); +  delete STX; +  Addr += 4; + +  // stx %i2, [%sp + 2127]       ;; save %i2 to the stack +  STX = BuildMI(V9::STXi, 3).addReg(i2).addReg(o6).addSImm(2127); +  *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*STX); +  delete STX; +  Addr += 4; + +  // +  // 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); +  *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*SH); +  delete SH; +  Addr += 4; + +  // 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); +  *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*OR); +  delete OR; +  Addr += 4; + +  // sllx %i1, 32, %i1            ;; shift those 10 bits to the upper word +  MachineInstr *SL = BuildMI(V9::SLLXi6, 3).addReg(i1).addSImm(32).addReg(i1); +  *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*SL); +  delete SL; +  Addr += 4; + +  // sethi %hi(Target), %i2    ;; extract bits 10-31 into the dest reg +  SH = BuildMI(V9::SETHI, 2).addSImm((Target >> 10) & 0x03fffff).addReg(i2); +  *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*SH); +  delete SH; +  Addr += 4; + +  // or %i1, %i2, %i2             ;; get upper word (in %i1) into %i2 +  OR = BuildMI(V9::ORr, 3).addReg(i1).addReg(i2).addReg(i2); +  *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*OR); +  delete OR; +  Addr += 4; + +  // 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); +  *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*OR); +  delete OR; +  Addr += 4; + +  // ldx [%sp + 2119], %i1       ;; restore %i1 -> 2119 = BIAS(2047) + 72 +  MachineInstr *LDX = BuildMI(V9::LDXi, 3).addReg(o6).addSImm(2119).addReg(i1); +  *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*LDX); +  delete LDX; +  Addr += 4; + +  // jmpl %i2, %g0, %g0          ;; indirect branch on %i2 +  MachineInstr *J = BuildMI(V9::JMPLRETr, 3).addReg(i2).addReg(g0).addReg(g0); +  *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*J); +  delete J; +  Addr += 4; + +  // ldx [%sp + 2127], %i2       ;; restore %i2 -> 2127 = BIAS(2047) + 80 +  LDX = BuildMI(V9::LDXi, 3).addReg(o6).addSImm(2127).addReg(i2); +  *((unsigned*)(intptr_t)Addr) = getBinaryCodeForInstr(*LDX); +  delete LDX; +  Addr += 4; + +  return Addr; +} -  int64_t NewVal = (int64_t)TheJITResolver->resolveFunctionReference(RetAddr); +void JITResolver::CompilationCallback() { +  uint64_t CameFrom = (uint64_t)(intptr_t)__builtin_return_address(0); +  int64_t Target = (int64_t)TheJITResolver->resolveFunctionReference(CameFrom); +  std::cerr << "In callback! Addr=0x" << std::hex << CameFrom << "\n";    // Rewrite the call target... so that we don't fault every time we execute    // the call. +#if 0    int64_t RealCallTarget = (int64_t)      ((NewVal - TheJITResolver->getCurrentPCValue()) >> 4); -  MachineInstr *MI = BuildMI(V9::CALL, 1); -  MI->addSignExtImmOperand(RealCallTarget); -  // FIXME: this could be in the wrong byte order!! -  *((unsigned*)(intptr_t)RetAddr) = TheJITResolver->getBinaryCodeForInstr(*MI); +  if (RealCallTarget >= (1<<22) || RealCallTarget <= -(1<<22)) { +    std::cerr << "Address out of bounds for 22bit BA: " << RealCallTarget<<"\n"; +    abort(); +  } +#endif + +  //uint64_t CurrPC    = TheJITResolver->getCurrentPCValue(); +  // we will insert 9 instructions before we do the actual jump +  //int64_t NewTarget  = (NewVal - 9*4 - InstAddr) >> 2; + +  static const unsigned i1 = SparcIntRegClass::i1, i2 = SparcIntRegClass::i2, +    i7 = SparcIntRegClass::i7, o6 = SparcIntRegClass::o6, +    o7 = SparcIntRegClass::o7, g0 = SparcIntRegClass::g0; + +  // Subtract 4 to overwrite the 'save' that's there now +  uint64_t InstAddr = CameFrom-4; + +  InstAddr = TheJITResolver->insertFarJumpAtAddr(Target, InstAddr); + +  // CODE SHOULD NEVER GO PAST THIS LOAD!! The real function should return to +  // the original caller, not here!! + +  // FIXME: add call 0 to make sure?!? + +  // =============== THE REAL STUB ENDS HERE ========================= + +  // What follows below is one-time restore code, because this callback may be +  // changing registers in unpredictible ways. However, since it is executed +  // only once per function (after the function is resolved, the callback is no +  // longer in the path), this has to be done only once. +  // +  // Thus, it is after the regular stub code. The call back returns to THIS +  // point, but every other call to the target function will execute the code +  // above. Hence, this code is one-time use. + +  uint64_t OneTimeRestore = InstAddr; + +  // restore %g0, 0, %g0 +  //MachineInstr *R = BuildMI(V9::RESTOREi, 3).addMReg(g0).addSImm(0) +  //                                          .addMReg(g0, MOTy::Def); +  //*((unsigned*)(intptr_t)InstAddr)=TheJITResolver->getBinaryCodeForInstr(*R); +  //delete R; + +  // FIXME: BuildMI() above crashes. Encode the instruction directly. +  // restore %g0, 0, %g0 +  *((unsigned*)(intptr_t)InstAddr) = 0x81e82000U; +  InstAddr += 4;   + +  InstAddr = TheJITResolver->insertFarJumpAtAddr(Target, InstAddr); + +  // FIXME: 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. +  /* +  MachineInstr *MI = BuildMI(V9::BA, 1).addSImm(RealCallTarget); +  *((unsigned*)(intptr_t)InstAddr) = TheJITResolver->getBinaryCodeForInstr(*MI);    delete MI; -   +  InstAddr += 4; + +  // Add another NOP +  MachineInstr *Nop = BuildMI(V9::NOP, 0); +  *((unsigned*)(intptr_t)InstAddr)=TheJITResolver->getBinaryCodeForInstr(*Nop); +  delete Nop; +  InstAddr += 4; + +  MachineInstr *BA = BuildMI(V9::BA, 1).addSImm(RealCallTarget-2); +  *((unsigned*)(intptr_t)InstAddr) = TheJITResolver->getBinaryCodeForInstr(*BA); +  delete BA; +  */ +    // Change the return address to reexecute the call instruction... -  StackPtr[1] -= 4; +  // The return address is really %o7, but will disappear after this function +  // returns, and the register windows are rotated away. +#if defined(sparc) || defined(__sparc__) || defined(__sparcv9) +  __asm__ __volatile__ ("or %%g0, %0, %%i7" : : "r" (OneTimeRestore-8)); +#endif  }  /// emitStubForFunction - This method is used by the JIT when it needs to emit @@ -122,26 +273,31 @@ void JITResolver::CompilationCallback() {  /// directly.  ///  uint64_t JITResolver::emitStubForFunction(Function *F) { -#if 0    MCE.startFunctionStub(*F, 6); -  MCE.emitByte(0xE8);   // Call with 32 bit pc-rel destination... -  uint64_t Address = addFunctionReference(MCE.getCurrentPCValue(), F); -  MCE.emitWord(Address-MCE.getCurrentPCValue()-4); +  std::cerr << "Emitting stub at addr: 0x"  +            << std::hex << MCE.getCurrentPCValue() << "\n"; -  MCE.emitByte(0xCD);   // Interrupt - Just a marker identifying the stub! -  return (intptr_t)MCE.finishFunctionStub(*F); -#endif -  MCE.startFunctionStub(*F, 6); +  unsigned o6 = SparcIntRegClass::o6; +  // save %sp, -192, %sp +  MachineInstr *SV = BuildMI(V9::SAVEi, 3).addReg(o6).addSImm(-192).addReg(o6); +  SparcV9.emitWord(SparcV9.getBinaryCodeForInstr(*SV)); +  delete SV;    int64_t CurrPC = MCE.getCurrentPCValue();    int64_t Addr = (int64_t)addFunctionReference(CurrPC, F); +    int64_t CallTarget = (Addr-CurrPC) >> 2; -  MachineInstr *Call = BuildMI(V9::CALL, 1); -  Call->addSignExtImmOperand(CallTarget); +  if (CallTarget >= (1 << 30) || CallTarget <= -(1 << 30)) { +    std::cerr << "Call target beyond 30 bit limit of CALL: " <<CallTarget<<"\n"; +    abort(); +  } +  // call CallTarget              ;; invoke the callback +  MachineInstr *Call = BuildMI(V9::CALL, 1).addSImm(CallTarget);    SparcV9.emitWord(SparcV9.getBinaryCodeForInstr(*Call));    delete Call; +  // nop                          ;; call delay slot    MachineInstr *Nop = BuildMI(V9::NOP, 0);    SparcV9.emitWord(SparcV9.getBinaryCodeForInstr(*Nop));    delete Nop; @@ -170,7 +326,25 @@ void SparcV9CodeEmitter::emitWord(unsigned Val) {    }  } -unsigned getRealRegNum(unsigned fakeReg, unsigned regClass) { +bool SparcV9CodeEmitter::isFPInstr(MachineInstr &MI) { +  for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) { +    const MachineOperand &MO = MI.getOperand(i); +    if (MO.isPhysicalRegister()) { +      unsigned fakeReg = MO.getReg(), realReg, regClass, regType; +      regType = TM.getRegInfo().getRegType(fakeReg); +      // At least map fakeReg into its class +      fakeReg = TM.getRegInfo().getClassRegNum(fakeReg, regClass); +      if (regClass == UltraSparcRegInfo::FPSingleRegType || +          regClass == UltraSparcRegInfo::FPDoubleRegType) +        return true; +    } +  } +  return false; +} + +unsigned  +SparcV9CodeEmitter::getRealRegNum(unsigned fakeReg, unsigned regClass, +                                  MachineInstr &MI) {    switch (regClass) {    case UltraSparcRegInfo::IntRegType: {      // Sparc manual, p31 @@ -199,11 +373,23 @@ unsigned getRealRegNum(unsigned fakeReg, unsigned regClass) {      return fakeReg;    }    case UltraSparcRegInfo::FloatCCRegType: { +    /* These are laid out %fcc0 - %fcc3 => 0 - 3, so are correct */      return fakeReg;    }    case UltraSparcRegInfo::IntCCRegType: { -    return fakeReg; +    static const unsigned FPInstrIntCCReg[]  = { 6 /* xcc */, 4  /* icc */ }; +    static const unsigned IntInstrIntCCReg[] = { 2 /* xcc */, 0  /* icc */ }; +     +    if (isFPInstr(MI)) { +      assert(fakeReg < sizeof(FPInstrIntCCReg)/sizeof(FPInstrIntCCReg[0]) +             && "Int CC register out of bounds for FPInstr IntCCReg map");       +      return FPInstrIntCCReg[fakeReg]; +    } else { +      assert(fakeReg < sizeof(IntInstrIntCCReg)/sizeof(IntInstrIntCCReg[0]) +             && "Int CC register out of bounds for IntInstr IntCCReg map"); +      return IntInstrIntCCReg[fakeReg]; +    }    }    default:      assert(0 && "Invalid unified register number in getRegType"); @@ -278,7 +464,9 @@ int64_t SparcV9CodeEmitter::getMachineOpValue(MachineInstr &MI,        std::cerr << "ERROR: PC relative disp unhandled:" << MO << "\n";        abort();      } -  } else if (MO.isPhysicalRegister()) { +  } else if (MO.isPhysicalRegister() || +             MO.getType() == MachineOperand::MO_CCRegister) +  {      // This is necessary because the Sparc doesn't actually lay out registers      // in the real fashion -- it skips those that it chooses not to allocate,      // i.e. those that are the SP, etc. @@ -287,7 +475,7 @@ int64_t SparcV9CodeEmitter::getMachineOpValue(MachineInstr &MI,      // At least map fakeReg into its class      fakeReg = TM.getRegInfo().getClassRegNum(fakeReg, regClass);      // Find the real register number for use in an instruction -    realReg = getRealRegNum(fakeReg, regClass); +    realReg = getRealRegNum(fakeReg, regClass, MI);      std::cerr << "Reg[" << std::dec << fakeReg << "] = " << realReg << "\n";      rv = realReg;    } else if (MO.isImmediate()) { @@ -327,13 +515,13 @@ int64_t SparcV9CodeEmitter::getMachineOpValue(MachineInstr &MI,    // are used in SPARC assembly. (Some of these make no sense in combination    // with some of the above; we'll trust that the instruction selector    // will not produce nonsense, and not check for valid combinations here.) -  if (MO.opLoBits32()) {          // %lo(val) +  if (MO.opLoBits32()) {          // %lo(val) == %lo() in Sparc ABI doc      return rv & 0x03ff; -  } else if (MO.opHiBits32()) {   // %lm(val) +  } else if (MO.opHiBits32()) {   // %lm(val) == %hi() in Sparc ABI doc      return (rv >> 10) & 0x03fffff; -  } else if (MO.opLoBits64()) {   // %hm(val) +  } else if (MO.opLoBits64()) {   // %hm(val) == %ulo() in Sparc ABI doc      return (rv >> 32) & 0x03ff; -  } else if (MO.opHiBits64()) {   // %hh(val) +  } else if (MO.opHiBits64()) {   // %hh(val) == %uhi() in Sparc ABI doc      return rv >> 42;    } else {                        // (unadorned) val      return rv; diff --git a/llvm/lib/Target/Sparc/SparcV9CodeEmitter.h b/llvm/lib/Target/Sparc/SparcV9CodeEmitter.h index 15cb13ccd41..d9a03e5b231 100644 --- a/llvm/lib/Target/Sparc/SparcV9CodeEmitter.h +++ b/llvm/lib/Target/Sparc/SparcV9CodeEmitter.h @@ -47,6 +47,10 @@ private:    void emitBasicBlock(MachineBasicBlock &MBB);    void* getGlobalAddress(GlobalValue *V, MachineInstr &MI,                           bool isPCRelative); +  bool isFPInstr(MachineInstr &MI); +  unsigned getRealRegNum(unsigned fakeReg, unsigned regClass, +                         MachineInstr &MI); +  };  #endif | 

