MipsJITInfo.cpp revision 263509
155320Stanimura//===-- MipsJITInfo.cpp - Implement the Mips JIT Interface ----------------===//
253553Stanimura//
353553Stanimura//                     The LLVM Compiler Infrastructure
453553Stanimura//
554377Stanimura// This file is distributed under the University of Illinois Open Source
654377Stanimura// License. See LICENSE.TXT for details.
754377Stanimura//
854377Stanimura//===----------------------------------------------------------------------===//
953553Stanimura//
1053553Stanimura// This file implements the JIT interfaces for the Mips target.
1153553Stanimura//
1253553Stanimura//===----------------------------------------------------------------------===//
1353553Stanimura
1453553Stanimura#define DEBUG_TYPE "jit"
1553553Stanimura#include "MipsJITInfo.h"
1653553Stanimura#include "MipsInstrInfo.h"
1753553Stanimura#include "MipsRelocations.h"
1853553Stanimura#include "MipsSubtarget.h"
1953553Stanimura#include "llvm/CodeGen/JITCodeEmitter.h"
2053553Stanimura#include "llvm/IR/Function.h"
2153553Stanimura#include "llvm/Support/Debug.h"
2253553Stanimura#include "llvm/Support/ErrorHandling.h"
2353553Stanimura#include "llvm/Support/Memory.h"
2453553Stanimura#include "llvm/Support/raw_ostream.h"
2553553Stanimura#include <cstdlib>
2653553Stanimurausing namespace llvm;
2753553Stanimura
2853553Stanimura
2953553Stanimuravoid MipsJITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
3053553Stanimura  unsigned NewAddr = (intptr_t)New;
3153553Stanimura  unsigned OldAddr = (intptr_t)Old;
3253553Stanimura  const unsigned NopInstr = 0x0;
3353553Stanimura
3453553Stanimura  // If the functions are in the same memory segment, insert PC-region branch.
3553553Stanimura  if ((NewAddr & 0xF0000000) == ((OldAddr + 4) & 0xF0000000)) {
3653553Stanimura    unsigned *OldInstruction = (unsigned *)Old;
3753553Stanimura    *OldInstruction = 0x08000000;
38119287Simp    unsigned JTargetAddr = NewAddr & 0x0FFFFFFC;
39119287Simp
4053553Stanimura    JTargetAddr >>= 2;
4182180Scg    *OldInstruction |= JTargetAddr;
4282180Scg
4377504Scg    // Insert a NOP.
4477504Scg    OldInstruction++;
4577504Scg    *OldInstruction = NopInstr;
4677504Scg
4777504Scg    sys::Memory::InvalidateInstructionCache(Old, 2 * 4);
4853553Stanimura  } else {
4953553Stanimura    // We need to clear hint bits from the instruction, in case it is 'jr ra'.
5053553Stanimura    const unsigned HintMask = 0xFFFFF83F, ReturnSequence = 0x03e00008;
5153553Stanimura    unsigned* CurrentInstr = (unsigned*)Old;
5253553Stanimura    unsigned CurrInstrHintClear = (*CurrentInstr) & HintMask;
5374763Scg    unsigned* NextInstr = CurrentInstr + 1;
5474763Scg    unsigned NextInstrHintClear = (*NextInstr) & HintMask;
5553553Stanimura
5677504Scg    // Do absolute jump if there are 2 or more instructions before return from
5755321Stanimura    // the old function.
5853553Stanimura    if ((CurrInstrHintClear != ReturnSequence) &&
5953553Stanimura        (NextInstrHintClear != ReturnSequence)) {
6053553Stanimura      const unsigned LuiT0Instr = 0x3c080000, AddiuT0Instr = 0x25080000;
6153553Stanimura      const unsigned JrT0Instr = 0x01000008;
6253553Stanimura      // lui  t0,  high 16 bit of the NewAddr
6353553Stanimura      (*(CurrentInstr++)) = LuiT0Instr | ((NewAddr & 0xffff0000) >> 16);
6455320Stanimura      // addiu  t0, t0, low 16 bit of the NewAddr
6577504Scg      (*(CurrentInstr++)) = AddiuT0Instr | (NewAddr & 0x0000ffff);
6653553Stanimura      // jr t0
6777504Scg      (*(CurrentInstr++)) = JrT0Instr;
6853553Stanimura      (*CurrentInstr) = NopInstr;
6953553Stanimura
7053553Stanimura      sys::Memory::InvalidateInstructionCache(Old, 4 * 4);
7153553Stanimura    } else {
7253553Stanimura      // Unsupported case
7353553Stanimura      report_fatal_error("MipsJITInfo::replaceMachineCodeForFunction");
7453553Stanimura    }
7553553Stanimura  }
7653553Stanimura}
7753553Stanimura
7853553Stanimura/// JITCompilerFunction - This contains the address of the JIT function used to
7953553Stanimura/// compile a function lazily.
8053553Stanimurastatic TargetJITInfo::JITCompilerFn JITCompilerFunction;
8153553Stanimura
8253553Stanimura// Get the ASMPREFIX for the current host.  This is often '_'.
8353553Stanimura#ifndef __USER_LABEL_PREFIX__
8453553Stanimura#define __USER_LABEL_PREFIX__
8553553Stanimura#endif
8653553Stanimura#define GETASMPREFIX2(X) #X
8753553Stanimura#define GETASMPREFIX(X) GETASMPREFIX2(X)
8853553Stanimura#define ASMPREFIX GETASMPREFIX(__USER_LABEL_PREFIX__)
8953553Stanimura
9064881Scg// CompilationCallback stub - We can't use a C function with inline assembly in
9164881Scg// it, because the prolog/epilog inserted by GCC won't work for us. Instead,
9264881Scg// write our own wrapper, which does things our way, so we have complete control
9364881Scg// over register saving and restoring. This code saves registers, calls
9464881Scg// MipsCompilationCallbackC and restores registers.
9564881Scgextern "C" {
9664881Scg#if defined (__mips__)
9764881Scgvoid MipsCompilationCallback();
9864881Scg
9964881Scg  asm(
10053553Stanimura    ".text\n"
10174763Scg    ".align 2\n"
10253553Stanimura    ".globl " ASMPREFIX "MipsCompilationCallback\n"
10364881Scg    ASMPREFIX "MipsCompilationCallback:\n"
10464881Scg    ".ent " ASMPREFIX "MipsCompilationCallback\n"
10553553Stanimura    ".frame  $sp, 32, $ra\n"
10664881Scg    ".set  noreorder\n"
10753553Stanimura    ".cpload $t9\n"
10874763Scg
10953553Stanimura    "addiu $sp, $sp, -64\n"
11053553Stanimura    ".cprestore 16\n"
11177504Scg
11277504Scg    // Save argument registers a0, a1, a2, a3, f12, f14 since they may contain
11377504Scg    // stuff for the real target function right now. We have to act as if this
11477504Scg    // whole compilation callback doesn't exist as far as the caller is
11577504Scg    // concerned. We also need to save the ra register since it contains the
11677504Scg    // original return address, and t8 register since it contains the address
11777504Scg    // of the end of function stub.
11877504Scg    "sw $a0, 20($sp)\n"
11977504Scg    "sw $a1, 24($sp)\n"
12077504Scg    "sw $a2, 28($sp)\n"
12177504Scg    "sw $a3, 32($sp)\n"
12277504Scg    "sw $ra, 36($sp)\n"
12377504Scg    "sw $t8, 40($sp)\n"
12477504Scg    "sdc1 $f12, 48($sp)\n"
12577504Scg    "sdc1 $f14, 56($sp)\n"
12677504Scg
12777504Scg    // t8 points at the end of function stub. Pass the beginning of the stub
12877504Scg    // to the MipsCompilationCallbackC.
12970134Scg    "addiu $a0, $t8, -16\n"
13053553Stanimura    "jal " ASMPREFIX "MipsCompilationCallbackC\n"
13153553Stanimura    "nop\n"
13270134Scg
13353553Stanimura    // Restore registers.
13470134Scg    "lw $a0, 20($sp)\n"
13570134Scg    "lw $a1, 24($sp)\n"
13653553Stanimura    "lw $a2, 28($sp)\n"
13777504Scg    "lw $a3, 32($sp)\n"
13870134Scg    "lw $ra, 36($sp)\n"
13970134Scg    "lw $t8, 40($sp)\n"
14077504Scg    "ldc1 $f12, 48($sp)\n"
14153553Stanimura    "ldc1 $f14, 56($sp)\n"
14270134Scg    "addiu $sp, $sp, 64\n"
14353553Stanimura
14453553Stanimura    // Jump to the (newly modified) stub to invoke the real function.
14553553Stanimura    "addiu $t8, $t8, -16\n"
14670134Scg    "jr $t8\n"
14753553Stanimura    "nop\n"
14870134Scg
14953553Stanimura    ".set  reorder\n"
15077504Scg    ".end " ASMPREFIX "MipsCompilationCallback\n"
15170134Scg      );
15277504Scg#else  // host != Mips
15353553Stanimura  void MipsCompilationCallback() {
15453553Stanimura    llvm_unreachable(
15553553Stanimura      "Cannot call MipsCompilationCallback() on a non-Mips arch!");
15653553Stanimura  }
15770134Scg#endif
15870134Scg}
15970134Scg
16070134Scg/// MipsCompilationCallbackC - This is the target-specific function invoked
16170134Scg/// by the function stub when we did not know the real target of a call.
16270134Scg/// This function must locate the start of the stub or call site and pass
16353553Stanimura/// it into the JIT compiler function.
16453553Stanimuraextern "C" void MipsCompilationCallbackC(intptr_t StubAddr) {
16553553Stanimura  // Get the address of the compiled code for this function.
16653553Stanimura  intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr);
16753553Stanimura
16853553Stanimura  // Rewrite the function stub so that we don't end up here every time we
16953553Stanimura  // execute the call. We're replacing the first four instructions of the
17053553Stanimura  // stub with code that jumps to the compiled function:
17153553Stanimura  //   lui $t9, %hi(NewVal)
17253553Stanimura  //   addiu $t9, $t9, %lo(NewVal)
17353553Stanimura  //   jr $t9
17453553Stanimura  //   nop
17553553Stanimura
17653553Stanimura  int Hi = ((unsigned)NewVal & 0xffff0000) >> 16;
17753553Stanimura  if ((NewVal & 0x8000) != 0)
17853553Stanimura    Hi++;
17953553Stanimura  int Lo = (int)(NewVal & 0xffff);
18053553Stanimura
18153553Stanimura  *(intptr_t *)(StubAddr) = 0xf << 26 | 25 << 16 | Hi;
18253553Stanimura  *(intptr_t *)(StubAddr + 4) = 9 << 26 | 25 << 21 | 25 << 16 | Lo;
18353553Stanimura  *(intptr_t *)(StubAddr + 8) = 25 << 21 | 8;
18453553Stanimura  *(intptr_t *)(StubAddr + 12) = 0;
18553553Stanimura
18653553Stanimura  sys::Memory::InvalidateInstructionCache((void*) StubAddr, 16);
18753553Stanimura}
18853553Stanimura
18953553StanimuraTargetJITInfo::LazyResolverFn MipsJITInfo::getLazyResolverFunction(
19053553Stanimura    JITCompilerFn F) {
19153553Stanimura  JITCompilerFunction = F;
19253553Stanimura  return MipsCompilationCallback;
19353553Stanimura}
19453553Stanimura
19553553StanimuraTargetJITInfo::StubLayout MipsJITInfo::getStubLayout() {
19653553Stanimura  // The stub contains 4 4-byte instructions, aligned at 4 bytes. See
19753553Stanimura  // emitFunctionStub for details.
19853553Stanimura  StubLayout Result = { 4*4, 4 };
19953553Stanimura  return Result;
20053553Stanimura}
20153553Stanimura
20253553Stanimuravoid *MipsJITInfo::emitFunctionStub(const Function *F, void *Fn,
20353553Stanimura                                    JITCodeEmitter &JCE) {
20453553Stanimura  JCE.emitAlignment(4);
20553553Stanimura  void *Addr = (void*) (JCE.getCurrentPCValue());
20653553Stanimura  if (!sys::Memory::setRangeWritable(Addr, 16))
20753553Stanimura    llvm_unreachable("ERROR: Unable to mark stub writable.");
20853553Stanimura
20953553Stanimura  intptr_t EmittedAddr;
21053553Stanimura  if (Fn != (void*)(intptr_t)MipsCompilationCallback)
21153553Stanimura    EmittedAddr = (intptr_t)Fn;
21253553Stanimura  else
21353553Stanimura    EmittedAddr = (intptr_t)MipsCompilationCallback;
21453553Stanimura
21553553Stanimura
21653553Stanimura  int Hi = ((unsigned)EmittedAddr & 0xffff0000) >> 16;
21753553Stanimura  if ((EmittedAddr & 0x8000) != 0)
21853553Stanimura    Hi++;
21953553Stanimura  int Lo = (int)(EmittedAddr & 0xffff);
22053553Stanimura
22153553Stanimura  // lui $t9, %hi(EmittedAddr)
22253553Stanimura  // addiu $t9, $t9, %lo(EmittedAddr)
22353553Stanimura  // jalr $t8, $t9
22453553Stanimura  // nop
22553553Stanimura  if (IsLittleEndian) {
22653553Stanimura    JCE.emitWordLE(0xf << 26 | 25 << 16 | Hi);
22753553Stanimura    JCE.emitWordLE(9 << 26 | 25 << 21 | 25 << 16 | Lo);
22853553Stanimura    JCE.emitWordLE(25 << 21 | 24 << 11 | 9);
22953553Stanimura    JCE.emitWordLE(0);
23053553Stanimura  } else {
23153553Stanimura    JCE.emitWordBE(0xf << 26 | 25 << 16 | Hi);
23253553Stanimura    JCE.emitWordBE(9 << 26 | 25 << 21 | 25 << 16 | Lo);
23353553Stanimura    JCE.emitWordBE(25 << 21 | 24 << 11 | 9);
23453553Stanimura    JCE.emitWordBE(0);
23553553Stanimura  }
23653553Stanimura
23753553Stanimura  sys::Memory::InvalidateInstructionCache(Addr, 16);
23853553Stanimura  if (!sys::Memory::setRangeExecutable(Addr, 16))
23953553Stanimura    llvm_unreachable("ERROR: Unable to mark stub executable.");
24053553Stanimura
24153553Stanimura  return Addr;
24253553Stanimura}
24353553Stanimura
24453553Stanimura/// relocate - Before the JIT can run a block of code that has been emitted,
24553553Stanimura/// it must rewrite the code to contain the actual addresses of any
24653553Stanimura/// referenced global symbols.
24753553Stanimuravoid MipsJITInfo::relocate(void *Function, MachineRelocation *MR,
24853553Stanimura                           unsigned NumRelocs, unsigned char *GOTBase) {
24953553Stanimura  for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
25053553Stanimura
25153553Stanimura    void *RelocPos = (char*) Function + MR->getMachineCodeOffset();
25253553Stanimura    intptr_t ResultPtr = (intptr_t) MR->getResultPointer();
25353553Stanimura
25453553Stanimura    switch ((Mips::RelocationType) MR->getRelocationType()) {
25553553Stanimura    case Mips::reloc_mips_pc16:
25653553Stanimura      ResultPtr = (((ResultPtr - (intptr_t) RelocPos) - 4) >> 2) & 0xffff;
25753553Stanimura      *((unsigned*) RelocPos) |= (unsigned) ResultPtr;
25853553Stanimura      break;
25953553Stanimura
26053553Stanimura    case Mips::reloc_mips_26:
26153553Stanimura      ResultPtr = (ResultPtr & 0x0fffffff) >> 2;
26253553Stanimura      *((unsigned*) RelocPos) |= (unsigned) ResultPtr;
26353553Stanimura      break;
26453553Stanimura
26553553Stanimura    case Mips::reloc_mips_hi:
26653553Stanimura      ResultPtr = ResultPtr >> 16;
26753553Stanimura      if ((((intptr_t) (MR->getResultPointer()) & 0xffff) >> 15) == 1) {
26853553Stanimura        ResultPtr += 1;
26953553Stanimura      }
27053553Stanimura      *((unsigned*) RelocPos) |= (unsigned) ResultPtr;
27153553Stanimura      break;
27253553Stanimura
27353553Stanimura    case Mips::reloc_mips_lo: {
27453553Stanimura      // Addend is needed for unaligned load/store instructions, where offset
27553553Stanimura      // for the second load/store in the expanded instruction sequence must
27653553Stanimura      // be modified by +1 or +3. Otherwise, Addend is 0.
27753553Stanimura      int Addend = *((unsigned*) RelocPos) & 0xffff;
27853553Stanimura      ResultPtr = (ResultPtr + Addend) & 0xffff;
27956249Scg      *((unsigned*) RelocPos) &= 0xffff0000;
28053553Stanimura      *((unsigned*) RelocPos) |= (unsigned) ResultPtr;
28153553Stanimura      break;
28256249Scg    }
28353553Stanimura    }
28453553Stanimura  }
28553553Stanimura}
28653553Stanimura