forked from OSchip/llvm-project
Initial ARM JIT support by Raul Fernandes Herbster.
llvm-svn: 37926
This commit is contained in:
parent
929624f461
commit
9546a5c7de
|
@ -23,6 +23,7 @@ namespace llvm {
|
|||
|
||||
class ARMTargetMachine;
|
||||
class FunctionPass;
|
||||
class MachineCodeEmitter;
|
||||
|
||||
// Enums corresponding to ARM condition codes
|
||||
namespace ARMCC {
|
||||
|
@ -88,6 +89,8 @@ inline static const char *ARMCondCodeToString(ARMCC::CondCodes CC) {
|
|||
|
||||
FunctionPass *createARMISelDag(ARMTargetMachine &TM);
|
||||
FunctionPass *createARMCodePrinterPass(std::ostream &O, ARMTargetMachine &TM);
|
||||
FunctionPass *createARMCodeEmitterPass(ARMTargetMachine &TM,
|
||||
MachineCodeEmitter &MCE);
|
||||
FunctionPass *createARMLoadStoreOptimizationPass();
|
||||
FunctionPass *createARMConstantIslandPass();
|
||||
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
//===-- ARM/ARMCodeEmitter.cpp - Convert ARM code to machine code ---------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the Raul Herbster (raulherbster [at] gmail [dot]
|
||||
// com) and is distributed under the University of Illinois Open Source License.
|
||||
// See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the pass that transforms the ARM machine instructions into
|
||||
// relocatable machine code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "arm-emitter"
|
||||
#include "ARMInstrInfo.h"
|
||||
#include "ARMSubtarget.h"
|
||||
#include "ARMTargetMachine.h"
|
||||
#include "ARM.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/CodeGen/MachineCodeEmitter.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
using namespace llvm;
|
||||
|
||||
STATISTIC(NumEmitted, "Number of machine instructions emitted");
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN Emitter : public MachineFunctionPass {
|
||||
const ARMInstrInfo *II;
|
||||
const TargetData *TD;
|
||||
TargetMachine &TM;
|
||||
MachineCodeEmitter &MCE;
|
||||
public:
|
||||
static char ID;
|
||||
explicit Emitter(TargetMachine &tm, MachineCodeEmitter &mce)
|
||||
: MachineFunctionPass((intptr_t)&ID), II(0), TD(0), TM(tm),
|
||||
MCE(mce) {}
|
||||
Emitter(TargetMachine &tm, MachineCodeEmitter &mce,
|
||||
const ARMInstrInfo &ii, const TargetData &td)
|
||||
: MachineFunctionPass((intptr_t)&ID), II(&ii), TD(&td), TM(tm),
|
||||
MCE(mce) {}
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF);
|
||||
|
||||
virtual const char *getPassName() const {
|
||||
return "ARM Machine Code Emitter";
|
||||
}
|
||||
|
||||
void emitInstruction(const MachineInstr &MI);
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
char Emitter::ID = 0;
|
||||
}
|
||||
|
||||
/// createARMCodeEmitterPass - Return a pass that emits the collected ARM code
|
||||
/// to the specified MCE object.
|
||||
FunctionPass *llvm::createARMCodeEmitterPass(ARMTargetMachine &TM,
|
||||
MachineCodeEmitter &MCE) {
|
||||
return new Emitter(TM, MCE);
|
||||
}
|
||||
|
||||
bool Emitter::runOnMachineFunction(MachineFunction &MF) {
|
||||
assert((MF.getTarget().getRelocationModel() != Reloc::Default ||
|
||||
MF.getTarget().getRelocationModel() != Reloc::Static) &&
|
||||
"JIT relocation model must be set to static or default!");
|
||||
II = ((ARMTargetMachine&)MF.getTarget()).getInstrInfo();
|
||||
TD = ((ARMTargetMachine&)MF.getTarget()).getTargetData();
|
||||
|
||||
do {
|
||||
MCE.startFunction(MF);
|
||||
for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
|
||||
MBB != E; ++MBB) {
|
||||
MCE.StartMachineBasicBlock(MBB);
|
||||
for (MachineBasicBlock::const_iterator I = MBB->begin(), E = MBB->end();
|
||||
I != E; ++I)
|
||||
emitInstruction(*I);
|
||||
}
|
||||
} while (MCE.finishFunction(MF));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Emitter::emitInstruction(const MachineInstr &MI) {
|
||||
NumEmitted++; // Keep track of the # of mi's emitted
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
//===-- ARMJITInfo.cpp - Implement the JIT interfaces for the ARM target --===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the Raul Herbster (raulherbster [at] gmail [dot]
|
||||
// com) and is distributed under the University of Illinois Open Source License.
|
||||
// See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the JIT interfaces for the ARM target.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "jit"
|
||||
#include "ARMJITInfo.h"
|
||||
#include "ARMRelocations.h"
|
||||
#include "ARMSubtarget.h"
|
||||
#include "llvm/CodeGen/MachineCodeEmitter.h"
|
||||
#include "llvm/Config/alloca.h"
|
||||
#include <cstdlib>
|
||||
using namespace llvm;
|
||||
|
||||
void ARMJITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
|
||||
unsigned char *OldByte = (unsigned char *)Old;
|
||||
*OldByte++ = 0xEA; // Emit B opcode.
|
||||
unsigned *OldWord = (unsigned *)OldByte;
|
||||
unsigned NewAddr = (intptr_t)New;
|
||||
unsigned OldAddr = (intptr_t)OldWord;
|
||||
*OldWord = NewAddr - OldAddr - 4; // Emit PC-relative addr of New code.
|
||||
}
|
||||
|
||||
/// JITCompilerFunction - This contains the address of the JIT function used to
|
||||
/// compile a function lazily.
|
||||
static TargetJITInfo::JITCompilerFn JITCompilerFunction;
|
||||
|
||||
// CompilationCallback stub - We can't use a C function with inline assembly in
|
||||
// it, because we 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.
|
||||
extern "C" {
|
||||
#if defined(__arm__)
|
||||
void ARMCompilationCallback(void);
|
||||
asm(
|
||||
".text\n"
|
||||
".align 2\n"
|
||||
".globl ARMCompilationCallback\n"
|
||||
"ARMCompilationCallback:\n"
|
||||
// save main registers
|
||||
"mov ip, sp\n"
|
||||
"stmfd sp!, {fp, ip, lr, pc}\n"
|
||||
"sub fp, ip, #4\n"
|
||||
// arguments to Compilation Callback
|
||||
// r0 - our lr (address of the call instruction in stub plus 4)
|
||||
// r1 - stub's lr (address of instruction that called the stub plus 4)
|
||||
"mov r0, fp\n" // stub's frame
|
||||
"mov r1, lr\n" // stub's lr
|
||||
"bl ARMCompilationCallbackC\n"
|
||||
// restore main registers
|
||||
"ldmfd sp, {fp, sp, pc}\n");
|
||||
#else // Not an ARM host
|
||||
void ARMCompilationCallback() {
|
||||
assert(0 && "Cannot call ARMCompilationCallback() on a non-ARM arch!\n");
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// ARMCompilationCallbackC - This is the target-specific function invoked by the
|
||||
/// function stub when we did not know the real target of a call. This function
|
||||
/// must locate the start of the stub or call site and pass it into the JIT
|
||||
/// compiler function.
|
||||
extern "C" void ARMCompilationCallbackC(intptr_t *StackPtr, intptr_t RetAddr) {
|
||||
intptr_t *RetAddrLoc = &StackPtr[-1];
|
||||
|
||||
assert(*RetAddrLoc == RetAddr &&
|
||||
"Could not find return address on the stack!");
|
||||
#if 0
|
||||
DOUT << "In callback! Addr=" << (void*)RetAddr
|
||||
<< " FP=" << (void*)StackPtr
|
||||
<< ": Resolving call to function: "
|
||||
<< TheVM->getFunctionReferencedName((void*)RetAddr) << "\n";
|
||||
#endif
|
||||
|
||||
// Sanity check to make sure this really is a branch and link instruction.
|
||||
assert(((unsigned char*)RetAddr-1)[3] == 0xEB && "Not a branch and link instr!");
|
||||
|
||||
intptr_t NewVal = (intptr_t)JITCompilerFunction((void*)RetAddr);
|
||||
|
||||
// Rewrite the call target... so that we don't end up here every time we
|
||||
// execute the call.
|
||||
*(intptr_t *)RetAddr = (intptr_t)(NewVal-RetAddr-4);
|
||||
|
||||
// Change the return address to reexecute the branch and link instruction...
|
||||
*RetAddrLoc -= 1;
|
||||
}
|
||||
|
||||
TargetJITInfo::LazyResolverFn
|
||||
ARMJITInfo::getLazyResolverFunction(JITCompilerFn F) {
|
||||
JITCompilerFunction = F;
|
||||
return ARMCompilationCallback;
|
||||
}
|
||||
|
||||
void *ARMJITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) {
|
||||
unsigned addr = (intptr_t)Fn-MCE.getCurrentPCValue()-4;
|
||||
// If this is just a call to an external function, emit a branch instead of a
|
||||
// call. The code is the same except for one bit of the last instruction.
|
||||
if (Fn != (void*)(intptr_t)ARMCompilationCallback) {
|
||||
MCE.startFunctionStub(4, 2);
|
||||
MCE.emitByte(0xEA); // branch to the corresponding function addr
|
||||
MCE.emitByte((unsigned char)(addr >> 0));
|
||||
MCE.emitByte((unsigned char)(addr >> 8));
|
||||
MCE.emitByte((unsigned char)(addr >> 16));
|
||||
return MCE.finishFunctionStub(0);
|
||||
} else {
|
||||
MCE.startFunctionStub(5, 2);
|
||||
MCE.emitByte(0xEB); // branch and link to the corresponding function addr
|
||||
}
|
||||
MCE.emitByte((unsigned char)(addr >> 0));
|
||||
MCE.emitByte((unsigned char)(addr >> 8));
|
||||
MCE.emitByte((unsigned char)(addr >> 16));
|
||||
|
||||
return MCE.finishFunctionStub(0);
|
||||
}
|
||||
|
||||
/// 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 ARMJITInfo::relocate(void *Function, MachineRelocation *MR,
|
||||
unsigned NumRelocs, unsigned char* GOTBase) {
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
//===- ARMJITInfo.h - ARM implementation of the JIT interface --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the Raul Herbster (raulherbster [at] gmail [dot]
|
||||
// com) and is distributed under the University of Illinois Open Source License.
|
||||
// See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the declaration of the ARMJITInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ARMJITINFO_H
|
||||
#define ARMJITINFO_H
|
||||
|
||||
#include "llvm/Target/TargetJITInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
class ARMTargetMachine;
|
||||
|
||||
class ARMJITInfo : public TargetJITInfo {
|
||||
ARMTargetMachine &TM;
|
||||
public:
|
||||
ARMJITInfo(ARMTargetMachine &tm) : TM(tm) {useGOT = 0;}
|
||||
|
||||
/// replaceMachineCodeForFunction - Make it so that calling the function
|
||||
/// whose machine code is at OLD turns into a call to NEW, perhaps by
|
||||
/// overwriting OLD with a branch to NEW. This is used for self-modifying
|
||||
/// code.
|
||||
///
|
||||
virtual void replaceMachineCodeForFunction(void *Old, void *New);
|
||||
|
||||
/// emitFunctionStub - Use the specified MachineCodeEmitter object to emit a
|
||||
/// small native function that simply calls the function at the specified
|
||||
/// address.
|
||||
virtual void *emitFunctionStub(void *Fn, MachineCodeEmitter &MCE);
|
||||
|
||||
/// getLazyResolverFunction - Expose the lazy resolver to the JIT.
|
||||
virtual LazyResolverFn getLazyResolverFunction(JITCompilerFn);
|
||||
|
||||
/// 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.
|
||||
virtual void relocate(void *Function, MachineRelocation *MR,
|
||||
unsigned NumRelocs, unsigned char* GOTBase);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
//===- ARMRelocations.h - ARM Code Relocations ------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file was developed by the Raul Herbster (raulherbster [at] gmail [dot]
|
||||
// com) and is distributed under the University of Illinois Open Source License.
|
||||
// See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the ARM target-specific relocation types.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef ARMRELOCATIONS_H
|
||||
#define ARMRELOCATIONS_H
|
||||
|
||||
#include "llvm/CodeGen/MachineRelocation.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace ARM {
|
||||
enum RelocationType {
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -36,12 +36,26 @@ namespace {
|
|||
|
||||
/// ThumbTargetMachine - Create an Thumb architecture model.
|
||||
///
|
||||
unsigned ThumbTargetMachine::getJITMatchQuality() {
|
||||
#if defined(__arm__)
|
||||
return 10;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned ThumbTargetMachine::getModuleMatchQuality(const Module &M) {
|
||||
std::string TT = M.getTargetTriple();
|
||||
if (TT.size() >= 6 && std::string(TT.begin(), TT.begin()+6) == "thumb-")
|
||||
return 20;
|
||||
|
||||
return M.getPointerSize() == Module::Pointer32;
|
||||
if (M.getEndianness() == Module::LittleEndian &&
|
||||
M.getPointerSize() == Module::Pointer32)
|
||||
return 10; // Weak match
|
||||
else if (M.getEndianness() != Module::AnyEndianness ||
|
||||
M.getPointerSize() != Module::AnyPointerSize)
|
||||
return 0; // Match for some other target
|
||||
|
||||
return getJITMatchQuality()/2;
|
||||
}
|
||||
|
||||
ThumbTargetMachine::ThumbTargetMachine(const Module &M, const std::string &FS)
|
||||
|
@ -66,14 +80,29 @@ ARMTargetMachine::ARMTargetMachine(const Module &M, const std::string &FS,
|
|||
std::string("e-p:32:32-f64:64:64-i64:64:64"))),
|
||||
InstrInfo(Subtarget),
|
||||
FrameInfo(Subtarget),
|
||||
JITInfo(*this),
|
||||
TLInfo(*this) {}
|
||||
|
||||
unsigned ARMTargetMachine::getJITMatchQuality() {
|
||||
#if defined(__thumb__)
|
||||
return 10;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned ARMTargetMachine::getModuleMatchQuality(const Module &M) {
|
||||
std::string TT = M.getTargetTriple();
|
||||
if (TT.size() >= 4 && std::string(TT.begin(), TT.begin()+4) == "arm-")
|
||||
return 20;
|
||||
|
||||
return M.getPointerSize() == Module::Pointer32;
|
||||
if (M.getEndianness() == Module::LittleEndian &&
|
||||
M.getPointerSize() == Module::Pointer32)
|
||||
return 10; // Weak match
|
||||
else if (M.getEndianness() != Module::AnyEndianness ||
|
||||
M.getPointerSize() != Module::AnyPointerSize)
|
||||
return 0; // Match for some other target
|
||||
|
||||
return getJITMatchQuality()/2;
|
||||
}
|
||||
|
||||
|
||||
|
@ -106,3 +135,21 @@ bool ARMTargetMachine::addAssemblyEmitter(FunctionPassManager &PM, bool Fast,
|
|||
PM.add(createARMCodePrinterPass(Out, *this));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool ARMTargetMachine::addCodeEmitter(FunctionPassManager &PM, bool Fast,
|
||||
MachineCodeEmitter &MCE) {
|
||||
// FIXME: Move this to TargetJITInfo!
|
||||
setRelocationModel(Reloc::Static);
|
||||
|
||||
// Machine code emitter pass for ARM.
|
||||
PM.add(createARMCodeEmitterPass(*this, MCE));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ARMTargetMachine::addSimpleCodeEmitter(FunctionPassManager &PM, bool Fast,
|
||||
MachineCodeEmitter &MCE) {
|
||||
// Machine code emitter pass for ARM.
|
||||
PM.add(createARMCodeEmitterPass(*this, MCE));
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "llvm/Target/TargetFrameInfo.h"
|
||||
#include "ARMInstrInfo.h"
|
||||
#include "ARMFrameInfo.h"
|
||||
#include "ARMJITInfo.h"
|
||||
#include "ARMSubtarget.h"
|
||||
#include "ARMISelLowering.h"
|
||||
|
||||
|
@ -32,6 +33,7 @@ class ARMTargetMachine : public LLVMTargetMachine {
|
|||
const TargetData DataLayout; // Calculates type size & alignment
|
||||
ARMInstrInfo InstrInfo;
|
||||
ARMFrameInfo FrameInfo;
|
||||
ARMJITInfo JITInfo;
|
||||
ARMTargetLowering TLInfo;
|
||||
|
||||
public:
|
||||
|
@ -39,6 +41,7 @@ public:
|
|||
|
||||
virtual const ARMInstrInfo *getInstrInfo() const { return &InstrInfo; }
|
||||
virtual const TargetFrameInfo *getFrameInfo() const { return &FrameInfo; }
|
||||
virtual TargetJITInfo *getJITInfo() { return &JITInfo; }
|
||||
virtual const MRegisterInfo *getRegisterInfo() const {
|
||||
return &InstrInfo.getRegisterInfo();
|
||||
}
|
||||
|
@ -48,6 +51,7 @@ public:
|
|||
return const_cast<ARMTargetLowering*>(&TLInfo);
|
||||
}
|
||||
static unsigned getModuleMatchQuality(const Module &M);
|
||||
static unsigned getJITMatchQuality();
|
||||
|
||||
virtual const TargetAsmInfo *createTargetAsmInfo() const;
|
||||
|
||||
|
@ -56,6 +60,10 @@ public:
|
|||
virtual bool addPreEmitPass(FunctionPassManager &PM, bool Fast);
|
||||
virtual bool addAssemblyEmitter(FunctionPassManager &PM, bool Fast,
|
||||
std::ostream &Out);
|
||||
virtual bool addCodeEmitter(FunctionPassManager &PM, bool Fast,
|
||||
MachineCodeEmitter &MCE);
|
||||
virtual bool addSimpleCodeEmitter(FunctionPassManager &PM, bool Fast,
|
||||
MachineCodeEmitter &MCE);
|
||||
};
|
||||
|
||||
/// ThumbTargetMachine - Thumb target machine.
|
||||
|
@ -64,6 +72,7 @@ class ThumbTargetMachine : public ARMTargetMachine {
|
|||
public:
|
||||
ThumbTargetMachine(const Module &M, const std::string &FS);
|
||||
|
||||
static unsigned getJITMatchQuality();
|
||||
static unsigned getModuleMatchQuality(const Module &M);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue