-//===- MipsJITInfo.cpp - Implement the JIT interfaces for the Mips target -===//
+//===-- MipsJITInfo.cpp - Implement the Mips JIT Interface ----------------===//
//
// The LLVM Compiler Infrastructure
//
#define GETASMPREFIX(X) GETASMPREFIX2(X)
#define ASMPREFIX GETASMPREFIX(__USER_LABEL_PREFIX__)
-// save registers, call MipsCompilationCallbackC, restore registers
+// CompilationCallback stub - We can't use a C function with inline assembly in
+// it, because the prolog/epilog inserted by GCC won't work for us. Instead,
+// write our own wrapper, which does things our way, so we have complete control
+// over register saving and restoring. This code saves registers, calls
+// MipsCompilationCallbackC and restores registers.
extern "C" {
#if defined (__mips__)
void MipsCompilationCallback();
".globl " ASMPREFIX "MipsCompilationCallback\n"
ASMPREFIX "MipsCompilationCallback:\n"
".ent " ASMPREFIX "MipsCompilationCallback\n"
+ ".frame $sp, 32, $ra\n"
".set noreorder\n"
".cpload $t9\n"
- ".frame $29, 32, $31\n"
-
- "addiu $sp, $sp, -40\n"
- "sw $a0, 4($sp)\n"
- "sw $a1, 8($sp)\n"
- "sw $a2, 12($sp)\n"
- "sw $a3, 20($sp)\n"
- "sw $ra, 24($sp)\n"
- "sw $v0, 28($sp)\n"
- "sw $v1, 32($sp)\n"
- "sw $t8, 36($sp)\n"
+
+ "addiu $sp, $sp, -64\n"
".cprestore 16\n"
+ // Save argument registers a0, a1, a2, a3, f12, f14 since they may contain
+ // stuff for the real target function right now. We have to act as if this
+ // whole compilation callback doesn't exist as far as the caller is
+ // concerned. We also need to save the ra register since it contains the
+ // original return address, and t8 register since it contains the address
+ // of the end of function stub.
+ "sw $a0, 20($sp)\n"
+ "sw $a1, 24($sp)\n"
+ "sw $a2, 28($sp)\n"
+ "sw $a3, 32($sp)\n"
+ "sw $ra, 36($sp)\n"
+ "sw $t8, 40($sp)\n"
+ "sdc1 $f12, 48($sp)\n"
+ "sdc1 $f14, 56($sp)\n"
+
+ // t8 points at the end of function stub. Pass the beginning of the stub
+ // to the MipsCompilationCallbackC.
"addiu $a0, $t8, -16\n"
- "jal " ASMPREFIX "MipsCompilationCallbackC\n"
+ "jal " ASMPREFIX "MipsCompilationCallbackC\n"
"nop\n"
- "lw $a0, 4($sp)\n"
- "lw $a1, 8($sp)\n"
- "lw $a2, 12($sp)\n"
- "lw $a3, 20($sp)\n"
- "lw $ra, 24($sp)\n"
- "lw $v0, 28($sp)\n"
- "lw $v1, 32($sp)\n"
- "lw $t8, 36($sp)\n"
- "addiu $sp, $sp, 40\n"
-
+ // Restore registers.
+ "lw $a0, 20($sp)\n"
+ "lw $a1, 24($sp)\n"
+ "lw $a2, 28($sp)\n"
+ "lw $a3, 32($sp)\n"
+ "lw $ra, 36($sp)\n"
+ "lw $t8, 40($sp)\n"
+ "ldc1 $f12, 48($sp)\n"
+ "ldc1 $f14, 56($sp)\n"
+ "addiu $sp, $sp, 64\n"
+
+ // Jump to the (newly modified) stub to invoke the real function.
"addiu $t8, $t8, -16\n"
"jr $t8\n"
"nop\n"
/// This function must locate the start of the stub or call site and pass
/// it into the JIT compiler function.
extern "C" void MipsCompilationCallbackC(intptr_t StubAddr) {
-
// Get the address of the compiled code for this function.
intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr);
- *(intptr_t *) (StubAddr) = 2 << 26 | ((NewVal & 0x0fffffff) >> 2); // J NewVal
- *(intptr_t *) (StubAddr + 4) = 0; // NOP
- *(intptr_t *) (StubAddr + 8) = 0; // NOP
- *(intptr_t *) (StubAddr + 12) = 0; // NOP
+ // Rewrite the function stub so that we don't end up here every time we
+ // execute the call. We're replacing the first four instructions of the
+ // stub with code that jumps to the compiled function:
+ // lui $t9, %hi(NewVal)
+ // addiu $t9, $t9, %lo(NewVal)
+ // jr $t9
+ // nop
+
+ int Hi = ((unsigned)NewVal & 0xffff0000) >> 16;
+ if ((NewVal & 0x8000) != 0)
+ Hi++;
+ int Lo = (int)(NewVal & 0xffff);
+
+ *(intptr_t *)(StubAddr) = 0xf << 26 | 25 << 16 | Hi;
+ *(intptr_t *)(StubAddr + 4) = 9 << 26 | 25 << 21 | 25 << 16 | Lo;
+ *(intptr_t *)(StubAddr + 8) = 25 << 21 | 8;
+ *(intptr_t *)(StubAddr + 12) = 0;
sys::Memory::InvalidateInstructionCache((void*) StubAddr, 16);
}
}
TargetJITInfo::StubLayout MipsJITInfo::getStubLayout() {
- StubLayout Result = { 24, 4 }; // {Size. Alignment} (of FunctionStub)
+ // The stub contains 4 4-byte instructions, aligned at 4 bytes. See
+ // emitFunctionStub for details.
+ StubLayout Result = { 4*4, 4 };
return Result;
}
JITCodeEmitter &JCE) {
JCE.emitAlignment(4);
void *Addr = (void*) (JCE.getCurrentPCValue());
-
- unsigned arg0 = ((intptr_t) MipsCompilationCallback >> 16);
- if ((((intptr_t) MipsCompilationCallback & 0xffff) >> 15) == 1) {
- arg0 += 1; // same hack as in relocate()
- }
-
- // LUI t9, %hi(MipsCompilationCallback)
- JCE.emitWordLE(0xf << 26 | 25 << 16 | arg0);
- // ADDiu t9, t9, %lo(MipsCompilationCallback)
- JCE.emitWordLE(9 << 26 | 25 << 21 | 25 << 16
- | ((intptr_t) MipsCompilationCallback & 0xffff));
- // JALR t8, t9
+ if (!sys::Memory::setRangeWritable(Addr, 16))
+ llvm_unreachable("ERROR: Unable to mark stub writable.");
+
+ intptr_t EmittedAddr;
+ if (Fn != (void*)(intptr_t)MipsCompilationCallback)
+ EmittedAddr = (intptr_t)Fn;
+ else
+ EmittedAddr = (intptr_t)MipsCompilationCallback;
+
+
+ int Hi = ((unsigned)EmittedAddr & 0xffff0000) >> 16;
+ if ((EmittedAddr & 0x8000) != 0)
+ Hi++;
+ int Lo = (int)(EmittedAddr & 0xffff);
+
+ // lui t9, %hi(EmittedAddr)
+ // addiu t9, t9, %lo(EmittedAddr)
+ // jalr t8, t9
+ // nop
+ JCE.emitWordLE(0xf << 26 | 25 << 16 | Hi);
+ JCE.emitWordLE(9 << 26 | 25 << 21 | 25 << 16 | Lo);
JCE.emitWordLE(25 << 21 | 24 << 11 | 9);
- JCE.emitWordLE(0); // NOP
+ JCE.emitWordLE(0);
- sys::Memory::InvalidateInstructionCache((void*) Addr, 16);
+ sys::Memory::InvalidateInstructionCache(Addr, 16);
+ if (!sys::Memory::setRangeExecutable(Addr, 16))
+ llvm_unreachable("ERROR: Unable to mark stub executable.");
return Addr;
}
intptr_t ResultPtr = (intptr_t) MR->getResultPointer();
switch ((Mips::RelocationType) MR->getRelocationType()) {
- case Mips::reloc_mips_pcrel:
+ case Mips::reloc_mips_pc16:
ResultPtr = (((ResultPtr - (intptr_t) RelocPos) - 4) >> 2) & 0xffff;
*((unsigned*) RelocPos) |= (unsigned) ResultPtr;
break;
- case Mips::reloc_mips_j_jal: {
+ case Mips::reloc_mips_26:
ResultPtr = (ResultPtr & 0x0fffffff) >> 2;
*((unsigned*) RelocPos) |= (unsigned) ResultPtr;
- }
break;
- case Mips::reloc_mips_hi: {
+ case Mips::reloc_mips_hi:
ResultPtr = ResultPtr >> 16;
-
- // see See MIPS Run Linux, chapter 9.4
if ((((intptr_t) (MR->getResultPointer()) & 0xffff) >> 15) == 1) {
ResultPtr += 1;
}
-
*((unsigned*) RelocPos) |= (unsigned) ResultPtr;
- }
break;
- case Mips::reloc_mips_lo:
- ResultPtr = ResultPtr & 0xffff;
+ case Mips::reloc_mips_lo: {
+ // Addend is needed for unaligned load/store instructions, where offset
+ // for the second load/store in the expanded instruction sequence must
+ // be modified by +1 or +3. Otherwise, Addend is 0.
+ int Addend = *((unsigned*) RelocPos) & 0xffff;
+ ResultPtr = (ResultPtr + Addend) & 0xffff;
+ *((unsigned*) RelocPos) &= 0xffff0000;
*((unsigned*) RelocPos) |= (unsigned) ResultPtr;
break;
-
- default:
- assert(0 && "MipsJITInfo.unknown relocation;");
+ }
}
}
}