diff options
author | Chris Lattner <sabre@nondot.org> | 2002-12-03 22:48:59 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2002-12-03 22:48:59 +0000 |
commit | 6710121b6bed5eef409b0840cf18ed62ecae1cd9 (patch) | |
tree | b390412091a4c964bfbb700bc09bef3eacb47f9c /tools | |
parent | f815aebd20823698fca5db54dc8e0332f93e7ca8 (diff) | |
download | external_llvm-6710121b6bed5eef409b0840cf18ed62ecae1cd9.zip external_llvm-6710121b6bed5eef409b0840cf18ed62ecae1cd9.tar.gz external_llvm-6710121b6bed5eef409b0840cf18ed62ecae1cd9.tar.bz2 |
Initial checkin of virtual machine implementation.
We can now run very trivial test cases
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@4894 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools')
-rw-r--r-- | tools/jello/Emitter.cpp | 74 | ||||
-rw-r--r-- | tools/jello/VM.cpp | 65 | ||||
-rw-r--r-- | tools/jello/VM.h | 50 | ||||
-rw-r--r-- | tools/jello/jello.cpp | 64 |
4 files changed, 199 insertions, 54 deletions
diff --git a/tools/jello/Emitter.cpp b/tools/jello/Emitter.cpp new file mode 100644 index 0000000..89695ad --- /dev/null +++ b/tools/jello/Emitter.cpp @@ -0,0 +1,74 @@ +//===-- Emitter.cpp - Write machine code to executable memory -------------===// +// +// This file defines a MachineCodeEmitter object that is used by Jello to write +// machine code to memory and remember where relocatable values lie. +// +//===----------------------------------------------------------------------===// + +#include "VM.h" +#include "llvm/CodeGen/MachineCodeEmitter.h" +#include "llvm/CodeGen/MachineFunction.h" + +namespace { + class Emitter : public MachineCodeEmitter { + VM &TheVM; + + unsigned char *CurBlock; + unsigned char *CurByte; + public: + Emitter(VM &vm) : TheVM(vm) {} + + virtual void startFunction(MachineFunction &F); + virtual void finishFunction(MachineFunction &F); + virtual void startBasicBlock(MachineBasicBlock &BB) {} + virtual void emitByte(unsigned char B); + virtual void emitPCRelativeDisp(Value *V); + }; +} + +MachineCodeEmitter *VM::createEmitter(VM &V) { + return new Emitter(V); +} + + +#define _POSIX_MAPPED_FILES +#include <unistd.h> +#include <sys/mman.h> + +static void *getMemory() { + return mmap(0, 4096*2, PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); +} + + +void Emitter::startFunction(MachineFunction &F) { + CurBlock = (unsigned char *)getMemory(); + CurByte = CurBlock; // Start writing at the beginning of the fn. +} + +#include <iostream> +#include "llvm/Function.h" + +void Emitter::finishFunction(MachineFunction &F) { + std::cerr << "Finished Code Generation of Function: " + << F.getFunction()->getName() << ": " << CurByte-CurBlock + << " bytes of text\n"; + TheVM.addGlobalMapping(F.getFunction(), CurBlock); +} + + + +void Emitter::emitByte(unsigned char B) { + *CurByte++ = B; // Write the byte to memory +} + + +// emitPCRelativeDisp - Just output a displacement that will cause a reference +// to the zero page, which will cause a seg-fault, causing things to get +// resolved on demand. Keep track of these markers. +// +void Emitter::emitPCRelativeDisp(Value *V) { + unsigned ZeroAddr = -(unsigned)CurByte; // Calculate displacement to null + *(unsigned*)CurByte = ZeroAddr; // 4 byte offset + CurByte += 4; +} diff --git a/tools/jello/VM.cpp b/tools/jello/VM.cpp new file mode 100644 index 0000000..497c42e --- /dev/null +++ b/tools/jello/VM.cpp @@ -0,0 +1,65 @@ +//===-- jello.cpp - LLVM Just in Time Compiler ----------------------------===// +// +// This tool implements a just-in-time compiler for LLVM, allowing direct +// execution of LLVM bytecode in an efficient manner. +// +//===----------------------------------------------------------------------===// + +#include "VM.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/CodeGen/MachineCodeEmitter.h" +#include "llvm/Function.h" +#include <iostream> + + +VM::~VM() { + delete MCE; +} + +/// setupPassManager - Initialize the VM PassManager object with all of the +/// passes needed for the target to generate code. +/// +void VM::setupPassManager() { + // Compile LLVM Code down to machine code in the intermediate representation + if (TM.addPassesToJITCompile(PM)) { + std::cerr << ExeName << ": target '" << TM.getName() + << "' doesn't support JIT compilation!\n"; + abort(); + } + + // Turn the machine code intermediate representation into bytes in memory that + // may be executed. + // + if (TM.addPassesToEmitMachineCode(PM, *MCE)) { + std::cerr << ExeName << ": target '" << TM.getName() + << "' doesn't support machine code emission!\n"; + abort(); + } +} + +int VM::run(Function *F) { + int(*PF)() = (int(*)())getPointerToFunction(F); + assert(PF != 0 && "Null pointer to function?"); + return PF(); +} + + +/// getPointerToFunction - This method is used to get the address of the +/// specified function, compiling it if neccesary. +/// +void *VM::getPointerToFunction(Function *F) { + void *&Addr = GlobalAddress[F]; // Function already code gen'd + if (Addr) return Addr; + + if (F->isExternal()) { + assert(0 && "VM::getPointerToFunction: Doesn't handle external fn's yet!"); + } + + // JIT all of the functions in the module. Eventually this will JIT functions + // on demand. This has the effect of populating all of the non-external + // functions into the GlobalAddress table. + PM.run(M); + + assert(Addr && "Code generation didn't add function to GlobalAddress table!"); + return Addr; +} diff --git a/tools/jello/VM.h b/tools/jello/VM.h new file mode 100644 index 0000000..5d0cd38 --- /dev/null +++ b/tools/jello/VM.h @@ -0,0 +1,50 @@ +//===-- VM.h - Definitions for Virtual Machine ------------------*- C++ -*-===// +// +// This file defines the top level Virtual Machine data structure. +// +//===----------------------------------------------------------------------===// + +#ifndef VM_H +#define VM_H + +#include "llvm/PassManager.h" +#include <string> +#include <map> + +class TargetMachine; +class Function; +class GlobalValue; +class MachineCodeEmitter; + +class VM { + std::string ExeName; + Module &M; // The LLVM program we are running + TargetMachine &TM; // The current target we are compiling to + PassManager PM; // Passes to compile a function + MachineCodeEmitter *MCE; // MCE object + + std::map<const GlobalValue*, void *> GlobalAddress; +public: + VM(const std::string &name, Module &m, TargetMachine &tm) + : ExeName(name), M(m), TM(tm) { + MCE = createEmitter(*this); // Initialize MCE + setupPassManager(); + } + + ~VM(); + + int run(Function *F); + + void addGlobalMapping(const Function *F, void *Addr) { + void *&CurVal = GlobalAddress[(const GlobalValue*)F]; + assert(CurVal == 0 && "GlobalMapping already established!"); + CurVal = Addr; + } + +private: + static MachineCodeEmitter *createEmitter(VM &V); + void setupPassManager(); + void *getPointerToFunction(Function *F); +}; + +#endif diff --git a/tools/jello/jello.cpp b/tools/jello/jello.cpp index d2ff586..52541f0 100644 --- a/tools/jello/jello.cpp +++ b/tools/jello/jello.cpp @@ -3,42 +3,14 @@ // This tool implements a just-in-time compiler for LLVM, allowing direct // execution of LLVM bytecode in an efficient manner. // -// FIXME: This code will get more object oriented as we get the call back -// intercept stuff implemented. -// //===----------------------------------------------------------------------===// #include "llvm/Module.h" -#include "llvm/PassManager.h" #include "llvm/Bytecode/Reader.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachineImpls.h" #include "Support/CommandLine.h" -#include "Support/Statistic.h" - - -#include "llvm/CodeGen/MachineCodeEmitter.h" -#include "llvm/CodeGen/MachineFunction.h" -struct JelloMachineCodeEmitter : public MachineCodeEmitter { - void startFunction(MachineFunction &F) { - std::cout << "\n**** Writing machine code for function: " - << F.getFunction()->getName() << "\n"; - } - void finishFunction(MachineFunction &F) { - std::cout << "\n"; - } - void startBasicBlock(MachineBasicBlock &BB) { - std::cout << "\n--- Basic Block: " << BB.getBasicBlock()->getName() << "\n"; - } - - void emitByte(unsigned char B) { - std::cout << "0x" << std::hex << (unsigned int)B << std::dec << " "; - } - void emitPCRelativeDisp(Value *V) { - std::cout << "<" << V->getName() << ": 0x00 0x00 0x00 0x00> "; - } -}; - +#include "VM.h" namespace { cl::opt<std::string> @@ -57,10 +29,8 @@ int main(int argc, char **argv) { // Allocate a target... in the future this will be controllable on the // command line. - std::auto_ptr<TargetMachine> target(allocateX86TargetMachine()); - assert(target.get() && "Could not allocate target machine!"); - - TargetMachine &Target = *target.get(); + std::auto_ptr<TargetMachine> Target(allocateX86TargetMachine()); + assert(Target.get() && "Could not allocate target machine!"); // Parse the input bytecode file... std::string ErrorMsg; @@ -71,29 +41,15 @@ int main(int argc, char **argv) { return 1; } - PassManager Passes; + // Create the virtual machine object... + VM TheVM(argv[0], *M.get(), *Target.get()); - // Compile LLVM Code down to machine code in the intermediate representation - if (Target.addPassesToJITCompile(Passes)) { - std::cerr << argv[0] << ": target '" << Target.getName() - << "' doesn't support JIT compilation!\n"; + Function *F = M.get()->getNamedFunction(MainFunction); + if (F == 0) { + std::cerr << "Could not find function '" << MainFunction <<"' in module!\n"; return 1; } - // Turn the machine code intermediate representation into bytes in memory that - // may be executed. - // - JelloMachineCodeEmitter MCE; - if (Target.addPassesToEmitMachineCode(Passes, MCE)) { - std::cerr << argv[0] << ": target '" << Target.getName() - << "' doesn't support machine code emission!\n"; - return 1; - } - - // JIT all of the methods in the module. Eventually this will JIT functions - // on demand. - Passes.run(*M.get()); - - return 0; + // Run the virtual machine... + return TheVM.run(F); } - |