aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2002-12-03 22:48:59 +0000
committerChris Lattner <sabre@nondot.org>2002-12-03 22:48:59 +0000
commit6710121b6bed5eef409b0840cf18ed62ecae1cd9 (patch)
treeb390412091a4c964bfbb700bc09bef3eacb47f9c /tools
parentf815aebd20823698fca5db54dc8e0332f93e7ca8 (diff)
downloadexternal_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.cpp74
-rw-r--r--tools/jello/VM.cpp65
-rw-r--r--tools/jello/VM.h50
-rw-r--r--tools/jello/jello.cpp64
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);
}
-