Initial ARM JIT support by Raul Fernandes Herbster.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@37926 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng 2007-07-05 21:15:40 +00:00
parent 27e9d457d4
commit 148b6a419f
7 changed files with 366 additions and 2 deletions

View File

@ -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();

View File

@ -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
}

View File

@ -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) {
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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);
};