Initial checkin of virtual machine implementation.
authorChris Lattner <sabre@nondot.org>
Tue, 3 Dec 2002 22:48:59 +0000 (22:48 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 3 Dec 2002 22:48:59 +0000 (22:48 +0000)
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

tools/jello/Emitter.cpp [new file with mode: 0644]
tools/jello/VM.cpp [new file with mode: 0644]
tools/jello/VM.h [new file with mode: 0644]
tools/jello/jello.cpp

diff --git a/tools/jello/Emitter.cpp b/tools/jello/Emitter.cpp
new file mode 100644 (file)
index 0000000..89695ad
--- /dev/null
@@ -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 (file)
index 0000000..497c42e
--- /dev/null
@@ -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 (file)
index 0000000..5d0cd38
--- /dev/null
@@ -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
index d2ff5861e090aa5bf2d7f57c75bd3be784e67b78..52541f012c7ad2fa8d52c9f9ecc3cab46110e939 100644 (file)
@@ -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);
 }
-