mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-19 19:29:31 +00:00
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
This commit is contained in:
parent
f815aebd20
commit
6710121b6b
74
tools/jello/Emitter.cpp
Normal file
74
tools/jello/Emitter.cpp
Normal file
@ -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;
|
||||
}
|
65
tools/jello/VM.cpp
Normal file
65
tools/jello/VM.cpp
Normal file
@ -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;
|
||||
}
|
50
tools/jello/VM.h
Normal file
50
tools/jello/VM.h
Normal file
@ -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
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user