From bba1b6df9a7ac36e3a479dfe953a9618c87db7bb Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 1 Jun 2003 23:24:36 +0000 Subject: [PATCH] Move target specific code to target files. The new MachineCodeEmitter class is actually target independent! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@6517 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/ExecutionEngine/JIT/Callback.cpp | 82 ------------------- lib/ExecutionEngine/JIT/JIT.cpp | 5 +- lib/ExecutionEngine/JIT/JIT.h | 29 +------ lib/ExecutionEngine/JIT/JITEmitter.cpp | 108 ++++++++++++++++--------- lib/ExecutionEngine/JIT/VM.cpp | 23 +----- lib/ExecutionEngine/JIT/VM.h | 29 +------ 6 files changed, 80 insertions(+), 196 deletions(-) delete mode 100644 lib/ExecutionEngine/JIT/Callback.cpp diff --git a/lib/ExecutionEngine/JIT/Callback.cpp b/lib/ExecutionEngine/JIT/Callback.cpp deleted file mode 100644 index 0cb612c77f8..00000000000 --- a/lib/ExecutionEngine/JIT/Callback.cpp +++ /dev/null @@ -1,82 +0,0 @@ -//===-- Callback.cpp - Trap handler for function resolution ---------------===// -// -// This file defines the handler which is invoked when a reference to a -// non-codegen'd function is found. This file defines target specific code -// which is used by the JIT. -// -//===----------------------------------------------------------------------===// - -#include "VM.h" -#include "Support/Statistic.h" -#include "llvm/CodeGen/MachineCodeEmitter.h" -#include - -static VM *TheVM = 0; - -// CompilationCallback - Invoked the first time that a call site is found, -// which causes lazy compilation of the target function. -// -void VM::CompilationCallback() { -#if defined(i386) || defined(__i386__) || defined(__x86__) - unsigned *StackPtr = (unsigned*)__builtin_frame_address(0); - unsigned RetAddr = (unsigned)__builtin_return_address(0); - - assert(StackPtr[1] == RetAddr && - "Could not find return address on the stack!"); - bool isStub = ((unsigned char*)RetAddr)[0] == 0xCD; // Interrupt marker? - - // The call instruction should have pushed the return value onto the stack... - RetAddr -= 4; // Backtrack to the reference itself... - - DEBUG(std::cerr << "In callback! Addr=0x" << std::hex << RetAddr - << " ESP=0x" << (unsigned)StackPtr << std::dec - << ": Resolving call to function: " - << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n"); - - // Sanity check to make sure this really is a call instruction... - assert(((unsigned char*)RetAddr)[-1] == 0xE8 && "Not a call instr!"); - - unsigned NewVal = (unsigned)TheVM->resolveFunctionReference((void*)RetAddr); - - // Rewrite the call target... so that we don't fault every time we execute - // the call. - *(unsigned*)RetAddr = NewVal-RetAddr-4; - - if (isStub) { - // If this is a stub, rewrite the call into an unconditional branch - // instruction so that two return addresses are not pushed onto the stack - // when the requested function finally gets called. This also makes the - // 0xCD byte (interrupt) dead, so the marker doesn't effect anything. - ((unsigned char*)RetAddr)[-1] = 0xE9; - } - - // Change the return address to reexecute the call instruction... - StackPtr[1] -= 5; -#else - abort(); -#endif -} - -/// emitStubForFunction - This virtual method is used by the JIT when it needs -/// to emit the address of a function for a function whose code has not yet -/// been generated. In order to do this, it generates a stub which jumps to -/// the lazy function compiler, which will eventually get fixed to call the -/// function directly. -/// -void *VM::emitStubForFunction(const Function &F) { -#if defined(i386) || defined(__i386__) || defined(__x86__) - MCE->startFunctionStub(F, 6); - MCE->emitByte(0xE8); // Call with 32 bit pc-rel destination... - MCE->emitGlobalAddress((GlobalValue*)&F, true); - MCE->emitByte(0xCD); // Interrupt - Just a marker identifying the stub! - return MCE->finishFunctionStub(F); -#else - abort(); -#endif -} - -void VM::registerCallback() { - TheVM = this; -} - - diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp index 95d7331f8c7..b0b6dea4727 100644 --- a/lib/ExecutionEngine/JIT/JIT.cpp +++ b/lib/ExecutionEngine/JIT/JIT.cpp @@ -43,7 +43,7 @@ ExecutionEngine *ExecutionEngine::createJIT(Module *M, unsigned Config) { if (Arch == "x86") { TargetMachineAllocator = allocateX86TargetMachine; } else if (Arch == "sparc") { - TargetMachineAllocator = allocateSparcTargetMachine; + //TargetMachineAllocator = allocateSparcTargetMachine; } if (TargetMachineAllocator) { @@ -65,11 +65,10 @@ VM::VM(Module *M, TargetMachine *tm) : ExecutionEngine(M), TM(*tm) { if (Arch == "x86") { MCE = createX86Emitter(*this); } else if (Arch == "sparc") { - MCE = createSparcEmitter(*this); + //MCE = createSparcEmitter(*this); } setupPassManager(); - registerCallback(); emitGlobals(); } diff --git a/lib/ExecutionEngine/JIT/JIT.h b/lib/ExecutionEngine/JIT/JIT.h index 58b7a3895b9..7c378c41c82 100644 --- a/lib/ExecutionEngine/JIT/JIT.h +++ b/lib/ExecutionEngine/JIT/JIT.h @@ -22,12 +22,6 @@ class VM : public ExecutionEngine { PassManager PM; // Passes to compile a function MachineCodeEmitter *MCE; // MCE object - // FunctionRefs - A mapping between addresses that refer to unresolved - // functions and the LLVM function object itself. This is used by the fault - // handler to lazily patch up references... - // - std::map FunctionRefs; - public: VM(Module *M, TargetMachine *tm); ~VM(); @@ -37,14 +31,6 @@ public: virtual int run(const std::string &FnName, const std::vector &Args); - void addFunctionRef(void *Ref, Function *F) { - FunctionRefs[Ref] = F; - } - - const std::string &getFunctionReferencedName(void *RefAddr); - - void *resolveFunctionReference(void *RefAddr); - /// getPointerToNamedFunction - This method returns the address of the /// specified function by using the dlsym function call. As such it is only /// useful for resolving library symbols, not code generated symbols. @@ -61,21 +47,14 @@ public: /// static void runAtExitHandlers(); + /// getPointerToFunction - This returns the address of the specified function, + /// compiling it if necessary. + void *getPointerToFunction(const Function *F); + private: static MachineCodeEmitter *createX86Emitter(VM &V); static MachineCodeEmitter *createSparcEmitter(VM &V); void setupPassManager(); - void *getPointerToFunction(const Function *F); - - void registerCallback(); - - /// emitStubForFunction - This method is used by the JIT when it needs to emit - /// the address of a function for a function whose code has not yet been - /// generated. In order to do this, it generates a stub which jumps to the - /// lazy function compiler, which will eventually get fixed to call the - /// function directly. - /// - void *emitStubForFunction(const Function &F); }; #endif diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index e6fe09b135e..215e9eb42b9 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -13,38 +13,45 @@ #include "llvm/Function.h" #include "Support/Statistic.h" +static VM *TheVM = 0; + namespace { Statistic<> NumBytes("jello", "Number of bytes of machine code compiled"); class Emitter : public MachineCodeEmitter { - VM &TheVM; - + // CurBlock - The start of the current block of memory. CurByte - The + // current byte being emitted to. unsigned char *CurBlock, *CurByte; // When outputting a function stub in the context of some other function, we // save CurBlock and CurByte here. unsigned char *SavedCurBlock, *SavedCurByte; - - std::vector > BBRefs; - std::map BBLocations; + + // ConstantPoolAddresses - Contains the location for each entry in the + // constant pool. std::vector ConstantPoolAddresses; public: - Emitter(VM &vm) : TheVM(vm) {} + Emitter(VM &vm) { TheVM = &vm; } virtual void startFunction(MachineFunction &F); virtual void finishFunction(MachineFunction &F); virtual void emitConstantPool(MachineConstantPool *MCP); - virtual void startBasicBlock(MachineBasicBlock &BB); virtual void startFunctionStub(const Function &F, unsigned StubSize); virtual void* finishFunctionStub(const Function &F); virtual void emitByte(unsigned char B); - virtual void emitPCRelativeDisp(Value *V); - virtual void emitGlobalAddress(GlobalValue *V, bool isPCRelative); - virtual void emitGlobalAddress(const std::string &Name, bool isPCRelative); - virtual void emitFunctionConstantValueAddress(unsigned ConstantNum, - int Offset); - private: - void emitAddress(void *Addr, bool isPCRelative); + virtual void emitWord(unsigned W); + + virtual uint64_t getGlobalValueAddress(GlobalValue *V); + virtual uint64_t getGlobalValueAddress(const std::string &Name); + virtual uint64_t getConstantPoolEntryAddress(unsigned Entry); + virtual uint64_t getCurrentPCValue(); + + // forceCompilationOf - Force the compilation of the specified function, and + // return its address, because we REALLY need the address now. + // + // FIXME: This is JIT specific! + // + virtual uint64_t forceCompilationOf(Function *F); }; } @@ -66,21 +73,13 @@ static void *getMemory(unsigned NumPages) { void Emitter::startFunction(MachineFunction &F) { - CurBlock = (unsigned char *)getMemory(8); + CurBlock = (unsigned char *)getMemory(16); CurByte = CurBlock; // Start writing at the beginning of the fn. - TheVM.addGlobalMapping(F.getFunction(), CurBlock); + TheVM->addGlobalMapping(F.getFunction(), CurBlock); } void Emitter::finishFunction(MachineFunction &F) { ConstantPoolAddresses.clear(); - for (unsigned i = 0, e = BBRefs.size(); i != e; ++i) { - unsigned Location = BBLocations[BBRefs[i].first]; - unsigned *Ref = BBRefs[i].second; - *Ref = Location-(unsigned)(intptr_t)Ref-4; - } - BBRefs.clear(); - BBLocations.clear(); - NumBytes += CurByte-CurBlock; DEBUG(std::cerr << "Finished CodeGen of [0x" << std::hex @@ -95,18 +94,12 @@ void Emitter::emitConstantPool(MachineConstantPool *MCP) { // For now we just allocate some memory on the heap, this can be // dramatically improved. const Type *Ty = ((Value*)Constants[i])->getType(); - void *Addr = malloc(TheVM.getTargetData().getTypeSize(Ty)); - TheVM.InitializeMemory(Constants[i], Addr); + void *Addr = malloc(TheVM->getTargetData().getTypeSize(Ty)); + TheVM->InitializeMemory(Constants[i], Addr); ConstantPoolAddresses.push_back(Addr); } } - -void Emitter::startBasicBlock(MachineBasicBlock &BB) { - BBLocations[BB.getBasicBlock()] = (unsigned)(intptr_t)CurByte; -} - - void Emitter::startFunctionStub(const Function &F, unsigned StubSize) { SavedCurBlock = CurBlock; SavedCurByte = CurByte; // FIXME: this is a huge waste of memory. @@ -129,6 +122,46 @@ void Emitter::emitByte(unsigned char B) { *CurByte++ = B; // Write the byte to memory } +void Emitter::emitWord(unsigned W) { + // FIXME: This won't work if the endianness of the host and target don't + // agree! (For a JIT this can't happen though. :) + *(unsigned*)CurByte = W; + CurByte += sizeof(unsigned); +} + + +uint64_t Emitter::getGlobalValueAddress(GlobalValue *V) { + // Try looking up the function to see if it is already compiled, if not return + // 0. + return (intptr_t)TheVM->getPointerToGlobalIfAvailable(V); +} +uint64_t Emitter::getGlobalValueAddress(const std::string &Name) { + return (intptr_t)TheVM->getPointerToNamedFunction(Name); +} + +// getConstantPoolEntryAddress - Return the address of the 'ConstantNum' entry +// in the constant pool that was last emitted with the 'emitConstantPool' +// method. +// +uint64_t Emitter::getConstantPoolEntryAddress(unsigned ConstantNum) { + assert(ConstantNum < ConstantPoolAddresses.size() && + "Invalid ConstantPoolIndex!"); + return (intptr_t)ConstantPoolAddresses[ConstantNum]; +} + +// getCurrentPCValue - This returns the address that the next emitted byte +// will be output to. +// +uint64_t Emitter::getCurrentPCValue() { + return (intptr_t)CurByte; +} + +uint64_t Emitter::forceCompilationOf(Function *F) { + return (intptr_t)TheVM->getPointerToFunction(F); +} + +#if 0 + // emitPCRelativeDisp - For functions, just output a displacement that will // cause a reference to the zero page, which will cause a seg-fault, causing @@ -157,23 +190,19 @@ void Emitter::emitAddress(void *Addr, bool isPCRelative) { void Emitter::emitGlobalAddress(GlobalValue *V, bool isPCRelative) { if (isPCRelative) { // must be a call, this is a major hack! // Try looking up the function to see if it is already compiled! - if (void *Addr = TheVM.getPointerToGlobalIfAvailable(V)) { + if (void *Addr = TheVM->getPointerToGlobalIfAvailable(V)) { emitAddress(Addr, isPCRelative); } else { // Function has not yet been code generated! - TheVM.addFunctionRef(CurByte, cast(V)); + TheVM->addFunctionRef(CurByte, cast(V)); // Delayed resolution... emitAddress((void*)VM::CompilationCallback, isPCRelative); } } else { - emitAddress(TheVM.getPointerToGlobal(V), isPCRelative); + emitAddress(TheVM->getPointerToGlobal(V), isPCRelative); } } -void Emitter::emitGlobalAddress(const std::string &Name, bool isPCRelative) { - emitAddress(TheVM.getPointerToNamedFunction(Name), isPCRelative); -} - void Emitter::emitFunctionConstantValueAddress(unsigned ConstantNum, int Offset) { assert(ConstantNum < ConstantPoolAddresses.size() && @@ -181,3 +210,4 @@ void Emitter::emitFunctionConstantValueAddress(unsigned ConstantNum, *(void**)CurByte = (char*)ConstantPoolAddresses[ConstantNum]+Offset; CurByte += 4; } +#endif diff --git a/lib/ExecutionEngine/JIT/VM.cpp b/lib/ExecutionEngine/JIT/VM.cpp index c6748fa1dc7..d5815e8dd88 100644 --- a/lib/ExecutionEngine/JIT/VM.cpp +++ b/lib/ExecutionEngine/JIT/VM.cpp @@ -36,22 +36,6 @@ void VM::setupPassManager() { } } -void *VM::resolveFunctionReference(void *RefAddr) { - Function *F = FunctionRefs[RefAddr]; - assert(F && "Reference address not known!"); - - void *Addr = getPointerToFunction(F); - assert(Addr && "Pointer to function unknown!"); - - FunctionRefs.erase(RefAddr); - return Addr; -} - -const std::string &VM::getFunctionReferencedName(void *RefAddr) { - assert(FunctionRefs[RefAddr] && "Function address unknown!"); - return FunctionRefs[RefAddr]->getName(); -} - /// getPointerToFunction - This method is used to get the address of the /// specified function, compiling it if neccesary. /// @@ -63,12 +47,7 @@ void *VM::getPointerToFunction(const Function *F) { return Addr = getPointerToNamedFunction(F->getName()); static bool isAlreadyCodeGenerating = false; - if (isAlreadyCodeGenerating) { - // Generate a function stub instead of reentering... - void *SAddr = emitStubForFunction(*F); - assert(SAddr && "Target machine doesn't support function stub generation!"); - return SAddr; - } + assert(!isAlreadyCodeGenerating && "ERROR: RECURSIVE COMPILATION DETECTED!"); // FIXME: JIT all of the functions in the module. Eventually this will JIT // functions on demand. This has the effect of populating all of the diff --git a/lib/ExecutionEngine/JIT/VM.h b/lib/ExecutionEngine/JIT/VM.h index 58b7a3895b9..7c378c41c82 100644 --- a/lib/ExecutionEngine/JIT/VM.h +++ b/lib/ExecutionEngine/JIT/VM.h @@ -22,12 +22,6 @@ class VM : public ExecutionEngine { PassManager PM; // Passes to compile a function MachineCodeEmitter *MCE; // MCE object - // FunctionRefs - A mapping between addresses that refer to unresolved - // functions and the LLVM function object itself. This is used by the fault - // handler to lazily patch up references... - // - std::map FunctionRefs; - public: VM(Module *M, TargetMachine *tm); ~VM(); @@ -37,14 +31,6 @@ public: virtual int run(const std::string &FnName, const std::vector &Args); - void addFunctionRef(void *Ref, Function *F) { - FunctionRefs[Ref] = F; - } - - const std::string &getFunctionReferencedName(void *RefAddr); - - void *resolveFunctionReference(void *RefAddr); - /// getPointerToNamedFunction - This method returns the address of the /// specified function by using the dlsym function call. As such it is only /// useful for resolving library symbols, not code generated symbols. @@ -61,21 +47,14 @@ public: /// static void runAtExitHandlers(); + /// getPointerToFunction - This returns the address of the specified function, + /// compiling it if necessary. + void *getPointerToFunction(const Function *F); + private: static MachineCodeEmitter *createX86Emitter(VM &V); static MachineCodeEmitter *createSparcEmitter(VM &V); void setupPassManager(); - void *getPointerToFunction(const Function *F); - - void registerCallback(); - - /// emitStubForFunction - This method is used by the JIT when it needs to emit - /// the address of a function for a function whose code has not yet been - /// generated. In order to do this, it generates a stub which jumps to the - /// lazy function compiler, which will eventually get fixed to call the - /// function directly. - /// - void *emitStubForFunction(const Function &F); }; #endif -- 2.34.1