1c5707112e7635d1dd2f2cc9c4f42e79a51302ccaJia Liu//===-- MipsJITInfo.cpp - Implement the Mips JIT Interface ----------------===//
2dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes//
3dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes//                     The LLVM Compiler Infrastructure
4dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes//
5dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes// This file is distributed under the University of Illinois Open Source
6dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes// License. See LICENSE.TXT for details.
7dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes//
8dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes//===----------------------------------------------------------------------===//
9dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes//
10dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes// This file implements the JIT interfaces for the Mips target.
11dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes//
12dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes//===----------------------------------------------------------------------===//
13dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
14dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#define DEBUG_TYPE "jit"
15dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#include "MipsJITInfo.h"
16dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#include "MipsInstrInfo.h"
17dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#include "MipsRelocations.h"
18dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#include "MipsSubtarget.h"
19dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#include "llvm/Function.h"
20dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#include "llvm/CodeGen/JITCodeEmitter.h"
21dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#include "llvm/Support/Debug.h"
22dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#include "llvm/Support/ErrorHandling.h"
23dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#include "llvm/Support/raw_ostream.h"
24dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#include "llvm/Support/Memory.h"
25dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#include <cstdlib>
26dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopesusing namespace llvm;
27dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
28dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
29dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopesvoid MipsJITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
30c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka  unsigned NewAddr = (intptr_t)New;
31c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka  unsigned OldAddr = (intptr_t)Old;
32c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka  const unsigned NopInstr = 0x0;
33c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka
34c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka  // If the functions are in the same memory segment, insert PC-region branch.
35c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka  if ((NewAddr & 0xF0000000) == ((OldAddr + 4) & 0xF0000000)) {
36c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    unsigned *OldInstruction = (unsigned *)Old;
37c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    *OldInstruction = 0x08000000;
38c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    unsigned JTargetAddr = NewAddr & 0x0FFFFFFC;
39c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka
40c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    JTargetAddr >>= 2;
41c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    *OldInstruction |= JTargetAddr;
42c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka
43c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    // Insert a NOP.
44c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    OldInstruction++;
45c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    *OldInstruction = NopInstr;
46c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka
47c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    sys::Memory::InvalidateInstructionCache(Old, 2 * 4);
48c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka  } else {
49c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    // We need to clear hint bits from the instruction, in case it is 'jr ra'.
50c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    const unsigned HintMask = 0xFFFFF83F, ReturnSequence = 0x03e00008;
51c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    unsigned* CurrentInstr = (unsigned*)Old;
52c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    unsigned CurrInstrHintClear = (*CurrentInstr) & HintMask;
53c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    unsigned* NextInstr = CurrentInstr + 1;
54c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    unsigned NextInstrHintClear = (*NextInstr) & HintMask;
55c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka
56c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    // Do absolute jump if there are 2 or more instructions before return from
57c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    // the old function.
58c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    if ((CurrInstrHintClear != ReturnSequence) &&
59c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka        (NextInstrHintClear != ReturnSequence)) {
60c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka      const unsigned LuiT0Instr = 0x3c080000, AddiuT0Instr = 0x25080000;
61c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka      const unsigned JrT0Instr = 0x01000008;
62c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka      // lui  t0,  high 16 bit of the NewAddr
63c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka      (*(CurrentInstr++)) = LuiT0Instr | ((NewAddr & 0xffff0000) >> 16);
64c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka      // addiu  t0, t0, low 16 bit of the NewAddr
65c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka      (*(CurrentInstr++)) = AddiuT0Instr | (NewAddr & 0x0000ffff);
66c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka      // jr t0
67c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka      (*(CurrentInstr++)) = JrT0Instr;
68c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka      (*CurrentInstr) = NopInstr;
69c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka
70c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka      sys::Memory::InvalidateInstructionCache(Old, 4 * 4);
71c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    } else {
72c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka      // Unsupported case
73c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka      report_fatal_error("MipsJITInfo::replaceMachineCodeForFunction");
74c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka    }
75c15ad8517719a525ac3b88b6c49b451160691eaaAkira Hatanaka  }
76dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes}
77dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
78dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes/// JITCompilerFunction - This contains the address of the JIT function used to
79dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes/// compile a function lazily.
80dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopesstatic TargetJITInfo::JITCompilerFn JITCompilerFunction;
81dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
82dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes// Get the ASMPREFIX for the current host.  This is often '_'.
83dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#ifndef __USER_LABEL_PREFIX__
84dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#define __USER_LABEL_PREFIX__
85dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#endif
86dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#define GETASMPREFIX2(X) #X
87dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#define GETASMPREFIX(X) GETASMPREFIX2(X)
88dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#define ASMPREFIX GETASMPREFIX(__USER_LABEL_PREFIX__)
89dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
90c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes// CompilationCallback stub - We can't use a C function with inline assembly in
91c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes// it, because the prolog/epilog inserted by GCC won't work for us. Instead,
92c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes// write our own wrapper, which does things our way, so we have complete control
93c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes// over register saving and restoring. This code saves registers, calls
94c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes// MipsCompilationCallbackC and restores registers.
95dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopesextern "C" {
96dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#if defined (__mips__)
97dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopesvoid MipsCompilationCallback();
98dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
99dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  asm(
100dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    ".text\n"
101dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    ".align 2\n"
102dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    ".globl " ASMPREFIX "MipsCompilationCallback\n"
103dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    ASMPREFIX "MipsCompilationCallback:\n"
104dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    ".ent " ASMPREFIX "MipsCompilationCallback\n"
10502dc51806e4c83437fb9c0f0507aef7111076937Bruno Cardoso Lopes    ".frame  $sp, 32, $ra\n"
106dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    ".set  noreorder\n"
107dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    ".cpload $t9\n"
108dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
10902dc51806e4c83437fb9c0f0507aef7111076937Bruno Cardoso Lopes    "addiu $sp, $sp, -64\n"
110dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    ".cprestore 16\n"
111dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
112c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    // Save argument registers a0, a1, a2, a3, f12, f14 since they may contain
113c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    // stuff for the real target function right now. We have to act as if this
114c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    // whole compilation callback doesn't exist as far as the caller is
115c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    // concerned. We also need to save the ra register since it contains the
116c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    // original return address, and t8 register since it contains the address
117c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    // of the end of function stub.
118c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    "sw $a0, 20($sp)\n"
119c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    "sw $a1, 24($sp)\n"
120c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    "sw $a2, 28($sp)\n"
121c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    "sw $a3, 32($sp)\n"
122c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    "sw $ra, 36($sp)\n"
123c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    "sw $t8, 40($sp)\n"
12402dc51806e4c83437fb9c0f0507aef7111076937Bruno Cardoso Lopes    "sdc1 $f12, 48($sp)\n"
12502dc51806e4c83437fb9c0f0507aef7111076937Bruno Cardoso Lopes    "sdc1 $f14, 56($sp)\n"
126c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes
127c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    // t8 points at the end of function stub. Pass the beginning of the stub
128c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    // to the MipsCompilationCallbackC.
129dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    "addiu $a0, $t8, -16\n"
130c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    "jal " ASMPREFIX "MipsCompilationCallbackC\n"
131dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    "nop\n"
132dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
133c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    // Restore registers.
134c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    "lw $a0, 20($sp)\n"
135c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    "lw $a1, 24($sp)\n"
136c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    "lw $a2, 28($sp)\n"
137c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    "lw $a3, 32($sp)\n"
138c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    "lw $ra, 36($sp)\n"
139c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    "lw $t8, 40($sp)\n"
14002dc51806e4c83437fb9c0f0507aef7111076937Bruno Cardoso Lopes    "ldc1 $f12, 48($sp)\n"
14102dc51806e4c83437fb9c0f0507aef7111076937Bruno Cardoso Lopes    "ldc1 $f14, 56($sp)\n"
14202dc51806e4c83437fb9c0f0507aef7111076937Bruno Cardoso Lopes    "addiu $sp, $sp, 64\n"
143c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes
144c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    // Jump to the (newly modified) stub to invoke the real function.
145dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    "addiu $t8, $t8, -16\n"
146dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    "jr $t8\n"
147dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    "nop\n"
148dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
149dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    ".set  reorder\n"
150dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    ".end " ASMPREFIX "MipsCompilationCallback\n"
151dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      );
152dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#else  // host != Mips
153dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  void MipsCompilationCallback() {
154dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    llvm_unreachable(
155dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      "Cannot call MipsCompilationCallback() on a non-Mips arch!");
156dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  }
157dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes#endif
158dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes}
159dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
160dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes/// MipsCompilationCallbackC - This is the target-specific function invoked
161dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes/// by the function stub when we did not know the real target of a call.
162dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes/// This function must locate the start of the stub or call site and pass
163dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes/// it into the JIT compiler function.
164dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopesextern "C" void MipsCompilationCallbackC(intptr_t StubAddr) {
165dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  // Get the address of the compiled code for this function.
166dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr);
167dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
168c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  // Rewrite the function stub so that we don't end up here every time we
169c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  // execute the call. We're replacing the first four instructions of the
170c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  // stub with code that jumps to the compiled function:
171c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  //   lui $t9, %hi(NewVal)
172c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  //   addiu $t9, $t9, %lo(NewVal)
173c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  //   jr $t9
174c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  //   nop
175c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes
176c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  int Hi = ((unsigned)NewVal & 0xffff0000) >> 16;
177c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  if ((NewVal & 0x8000) != 0)
178c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    Hi++;
179c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  int Lo = (int)(NewVal & 0xffff);
180c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes
181c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  *(intptr_t *)(StubAddr) = 0xf << 26 | 25 << 16 | Hi;
182c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  *(intptr_t *)(StubAddr + 4) = 9 << 26 | 25 << 21 | 25 << 16 | Lo;
183c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  *(intptr_t *)(StubAddr + 8) = 25 << 21 | 8;
184c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  *(intptr_t *)(StubAddr + 12) = 0;
185dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
186dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  sys::Memory::InvalidateInstructionCache((void*) StubAddr, 16);
187dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes}
188dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
189dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso LopesTargetJITInfo::LazyResolverFn MipsJITInfo::getLazyResolverFunction(
190dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    JITCompilerFn F) {
191dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  JITCompilerFunction = F;
192dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  return MipsCompilationCallback;
193dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes}
194dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
195dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso LopesTargetJITInfo::StubLayout MipsJITInfo::getStubLayout() {
196c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  // The stub contains 4 4-byte instructions, aligned at 4 bytes. See
197c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  // emitFunctionStub for details.
198c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  StubLayout Result = { 4*4, 4 };
199dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  return Result;
200dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes}
201dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
202864f66085cd9543070ef01b9f7371c110ecd7898Akira Hatanakavoid *MipsJITInfo::emitFunctionStub(const Function *F, void *Fn,
203864f66085cd9543070ef01b9f7371c110ecd7898Akira Hatanaka                                    JITCodeEmitter &JCE) {
204dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  JCE.emitAlignment(4);
205dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  void *Addr = (void*) (JCE.getCurrentPCValue());
206c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  if (!sys::Memory::setRangeWritable(Addr, 16))
207c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    llvm_unreachable("ERROR: Unable to mark stub writable.");
208c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes
209c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  intptr_t EmittedAddr;
210c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  if (Fn != (void*)(intptr_t)MipsCompilationCallback)
211c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    EmittedAddr = (intptr_t)Fn;
212c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  else
213c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    EmittedAddr = (intptr_t)MipsCompilationCallback;
214c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes
215c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes
216c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  int Hi = ((unsigned)EmittedAddr & 0xffff0000) >> 16;
217c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  if ((EmittedAddr & 0x8000) != 0)
218c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    Hi++;
219c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  int Lo = (int)(EmittedAddr & 0xffff);
220c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes
221c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  // lui t9, %hi(EmittedAddr)
222c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  // addiu t9, t9, %lo(EmittedAddr)
223c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  // jalr t8, t9
224c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  // nop
225c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  JCE.emitWordLE(0xf << 26 | 25 << 16 | Hi);
226c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  JCE.emitWordLE(9 << 26 | 25 << 21 | 25 << 16 | Lo);
227dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  JCE.emitWordLE(25 << 21 | 24 << 11 | 9);
228c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  JCE.emitWordLE(0);
229dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
230c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  sys::Memory::InvalidateInstructionCache(Addr, 16);
231c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes  if (!sys::Memory::setRangeExecutable(Addr, 16))
232c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    llvm_unreachable("ERROR: Unable to mark stub executable.");
233dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
234dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  return Addr;
235dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes}
236dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
237dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes/// relocate - Before the JIT can run a block of code that has been emitted,
238dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes/// it must rewrite the code to contain the actual addresses of any
239dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes/// referenced global symbols.
240dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopesvoid MipsJITInfo::relocate(void *Function, MachineRelocation *MR,
241864f66085cd9543070ef01b9f7371c110ecd7898Akira Hatanaka                           unsigned NumRelocs, unsigned char *GOTBase) {
242dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
243dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
244dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    void *RelocPos = (char*) Function + MR->getMachineCodeOffset();
245dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    intptr_t ResultPtr = (intptr_t) MR->getResultPointer();
246dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
247dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    switch ((Mips::RelocationType) MR->getRelocationType()) {
2483aa035fa0c27d3ea2a834868f680bcbfe7eb0de7Bruno Cardoso Lopes    case Mips::reloc_mips_pc16:
249dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      ResultPtr = (((ResultPtr - (intptr_t) RelocPos) - 4) >> 2) & 0xffff;
250dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      *((unsigned*) RelocPos) |= (unsigned) ResultPtr;
251dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      break;
252dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
253c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    case Mips::reloc_mips_26:
254dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      ResultPtr = (ResultPtr & 0x0fffffff) >> 2;
255dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      *((unsigned*) RelocPos) |= (unsigned) ResultPtr;
256dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      break;
257dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
258c4cc40c001e23dbeb6cb9953715177ccb314fbf1Bruno Cardoso Lopes    case Mips::reloc_mips_hi:
259dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      ResultPtr = ResultPtr >> 16;
260dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      if ((((intptr_t) (MR->getResultPointer()) & 0xffff) >> 15) == 1) {
261dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes        ResultPtr += 1;
262dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      }
263dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      *((unsigned*) RelocPos) |= (unsigned) ResultPtr;
264dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      break;
265dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes
266ad6eef4a6518ea5736cfec60b174019be805060dBruno Cardoso Lopes    case Mips::reloc_mips_lo: {
267ad6eef4a6518ea5736cfec60b174019be805060dBruno Cardoso Lopes      // Addend is needed for unaligned load/store instructions, where offset
268ad6eef4a6518ea5736cfec60b174019be805060dBruno Cardoso Lopes      // for the second load/store in the expanded instruction sequence must
269ad6eef4a6518ea5736cfec60b174019be805060dBruno Cardoso Lopes      // be modified by +1 or +3. Otherwise, Addend is 0.
270ad6eef4a6518ea5736cfec60b174019be805060dBruno Cardoso Lopes      int Addend = *((unsigned*) RelocPos) & 0xffff;
271ad6eef4a6518ea5736cfec60b174019be805060dBruno Cardoso Lopes      ResultPtr = (ResultPtr + Addend) & 0xffff;
272ad6eef4a6518ea5736cfec60b174019be805060dBruno Cardoso Lopes      *((unsigned*) RelocPos) &= 0xffff0000;
273dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      *((unsigned*) RelocPos) |= (unsigned) ResultPtr;
274dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes      break;
275ad6eef4a6518ea5736cfec60b174019be805060dBruno Cardoso Lopes    }
276dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes    }
277dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes  }
278dca6cdd6a14195c3ebbbb5d2c668445be119aaecBruno Cardoso Lopes}
279