From: Evan Cheng Date: Thu, 5 Jul 2007 21:15:40 +0000 (+0000) Subject: Initial ARM JIT support by Raul Fernandes Herbster. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=148b6a419fbb20e2224a1b92c499d51513b9bc27;p=oota-llvm.git 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 --- diff --git a/lib/Target/ARM/ARM.h b/lib/Target/ARM/ARM.h index 1d626d1c885..8134dcc4669 100644 --- a/lib/Target/ARM/ARM.h +++ b/lib/Target/ARM/ARM.h @@ -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(); diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp new file mode 100644 index 00000000000..e2350e2692b --- /dev/null +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -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 +} diff --git a/lib/Target/ARM/ARMJITInfo.cpp b/lib/Target/ARM/ARMJITInfo.cpp new file mode 100644 index 00000000000..05dbd3ce022 --- /dev/null +++ b/lib/Target/ARM/ARMJITInfo.cpp @@ -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 +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) { + +} diff --git a/lib/Target/ARM/ARMJITInfo.h b/lib/Target/ARM/ARMJITInfo.h new file mode 100644 index 00000000000..fc33cc25454 --- /dev/null +++ b/lib/Target/ARM/ARMJITInfo.h @@ -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 diff --git a/lib/Target/ARM/ARMRelocations.h b/lib/Target/ARM/ARMRelocations.h new file mode 100644 index 00000000000..f6c02af4679 --- /dev/null +++ b/lib/Target/ARM/ARMRelocations.h @@ -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 + diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp index fc03da1a8da..9c86e7b6658 100644 --- a/lib/Target/ARM/ARMTargetMachine.cpp +++ b/lib/Target/ARM/ARMTargetMachine.cpp @@ -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; +} diff --git a/lib/Target/ARM/ARMTargetMachine.h b/lib/Target/ARM/ARMTargetMachine.h index a50275c675f..183a5827671 100644 --- a/lib/Target/ARM/ARMTargetMachine.h +++ b/lib/Target/ARM/ARMTargetMachine.h @@ -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(&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); };