llvm-6502/lib/Target/Sparc/SparcJITInfo.cpp
Chandler Carruth 974a445bd9 Re-sort all of the includes with ./utils/sort_includes.py so that
subsequent changes are easier to review. About to fix some layering
issues, and wanted to separate out the necessary churn.

Also comment and sink the include of "Windows.h" in three .inc files to
match the usage in Memory.inc.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@198685 91177308-0d34-0410-b5e6-96231b3b80d8
2014-01-07 11:48:04 +00:00

165 lines
5.2 KiB
C++

//===-- SparcJITInfo.cpp - Implement the Sparc JIT Interface --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the JIT interfaces for the Sparc target.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "jit"
#include "SparcJITInfo.h"
#include "SparcRelocations.h"
#include "llvm/CodeGen/JITCodeEmitter.h"
#include "llvm/Support/Memory.h"
using namespace llvm;
/// JITCompilerFunction - This contains the address of the JIT function used to
/// compile a function lazily.
static TargetJITInfo::JITCompilerFn JITCompilerFunction;
extern "C" void SparcCompilationCallback();
extern "C" {
#if defined (__sparc__)
asm(
".text\n"
"\t.align 4\n"
"\t.global SparcCompilationCallback\n"
"\t.type SparcCompilationCallback, #function\n"
"SparcCompilationCallback:\n"
// Save current register window.
"\tsave %sp, -192, %sp\n"
// stubaddr+4 is in %g1.
"\tcall SparcCompilationCallbackC\n"
"\t sub %g1, 4, %o0\n"
// restore original register window and
// copy %o0 to %g1
"\t restore %o0, 0, %g1\n"
// call the new stub
"\tjmp %g1\n"
"\t nop\n"
"\t.size SparcCompilationCallback, .-SparcCompilationCallback"
);
#else
void SparcCompilationCallback() {
llvm_unreachable(
"Cannot call SparcCompilationCallback() on a non-sparc arch!");
}
#endif
}
#define HI(Val) (((unsigned)(Val)) >> 10)
#define LO(Val) (((unsigned)(Val)) & 0x3FF)
#define SETHI_INST(imm, rd) (0x01000000 | ((rd) << 25) | ((imm) & 0x3FFFFF))
#define JMP_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x38 << 19) \
| ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF))
#define NOP_INST SETHI_INST(0, 0)
extern "C" void *SparcCompilationCallbackC(intptr_t StubAddr) {
// Get the address of the compiled code for this function.
intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr);
// Rewrite the function stub so that we don't end up here every time we
// execute the call. We're replacing the first three instructions of the
// stub with code that jumps to the compiled function:
// sethi %hi(NewVal), %g1
// jmp %g1+%lo(NewVal)
// nop
*(intptr_t *)(StubAddr) = SETHI_INST(HI(NewVal), 1);
*(intptr_t *)(StubAddr + 4) = JMP_INST(1, LO(NewVal), 0);
*(intptr_t *)(StubAddr + 8) = NOP_INST;
sys::Memory::InvalidateInstructionCache((void*) StubAddr, 12);
return (void*)StubAddr;
}
void SparcJITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
assert(0 && "FIXME: Implement SparcJITInfo::replaceMachineCodeForFunction");
}
TargetJITInfo::StubLayout SparcJITInfo::getStubLayout() {
// The stub contains 3 4-byte instructions, aligned at 4 bytes. See
// emitFunctionStub for details.
StubLayout Result = { 3*4, 4 };
return Result;
}
void *SparcJITInfo::emitFunctionStub(const Function *F, void *Fn,
JITCodeEmitter &JCE)
{
JCE.emitAlignment(4);
void *Addr = (void*) (JCE.getCurrentPCValue());
if (!sys::Memory::setRangeWritable(Addr, 12))
llvm_unreachable("ERROR: Unable to mark stub writable.");
intptr_t EmittedAddr;
if (Fn != (void*)(intptr_t)SparcCompilationCallback)
EmittedAddr = (intptr_t)Fn;
else
EmittedAddr = (intptr_t)SparcCompilationCallback;
// sethi %hi(EmittedAddr), %g1
// jmp %g1+%lo(EmittedAddr), %g1
// nop
JCE.emitWordBE(SETHI_INST(HI(EmittedAddr), 1));
JCE.emitWordBE(JMP_INST(1, LO(EmittedAddr), 1));
JCE.emitWordBE(NOP_INST);
sys::Memory::InvalidateInstructionCache(Addr, 12);
if (!sys::Memory::setRangeExecutable(Addr, 12))
llvm_unreachable("ERROR: Unable to mark stub executable.");
return Addr;
}
TargetJITInfo::LazyResolverFn
SparcJITInfo::getLazyResolverFunction(JITCompilerFn F) {
JITCompilerFunction = F;
return SparcCompilationCallback;
}
/// relocate - Before the JIT can run a block of code that has been emitted,
/// it must rewrite the code to contain the actual addresses of any
/// referenced global symbols.
void SparcJITInfo::relocate(void *Function, MachineRelocation *MR,
unsigned NumRelocs, unsigned char *GOTBase) {
for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
void *RelocPos = (char*) Function + MR->getMachineCodeOffset();
intptr_t ResultPtr = (intptr_t) MR->getResultPointer();
switch ((SP::RelocationType) MR->getRelocationType()) {
case SP::reloc_sparc_hi:
ResultPtr = (ResultPtr >> 10) & 0x3fffff;
break;
case SP::reloc_sparc_lo:
ResultPtr = (ResultPtr & 0x3ff);
break;
case SP::reloc_sparc_pc30:
ResultPtr = ((ResultPtr - (intptr_t)RelocPos) >> 2) & 0x3fffffff;
break;
case SP::reloc_sparc_pc22:
ResultPtr = ((ResultPtr - (intptr_t)RelocPos) >> 2) & 0x3fffff;
break;
case SP::reloc_sparc_pc19:
ResultPtr = ((ResultPtr - (intptr_t)RelocPos) >> 2) & 0x7ffff;
break;
}
*((unsigned*) RelocPos) |= (unsigned) ResultPtr;
}
}