mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-05-15 00:38:42 +00:00
Substantial changes to refactor LLI to incorporate both the Jello JIT and
the traditional LLI interpreter git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@5125 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
b76d4965c1
commit
fe11a97fcd
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include "Interpreter.h"
|
#include "Interpreter.h"
|
||||||
#include "ExecutionAnnotations.h"
|
#include "ExecutionAnnotations.h"
|
||||||
|
#include "llvm/GlobalVariable.h"
|
||||||
|
#include "llvm/Function.h"
|
||||||
#include "llvm/iPHINode.h"
|
#include "llvm/iPHINode.h"
|
||||||
#include "llvm/iOther.h"
|
#include "llvm/iOther.h"
|
||||||
#include "llvm/iTerminators.h"
|
#include "llvm/iTerminators.h"
|
||||||
@ -13,7 +15,6 @@
|
|||||||
#include "llvm/DerivedTypes.h"
|
#include "llvm/DerivedTypes.h"
|
||||||
#include "llvm/Constants.h"
|
#include "llvm/Constants.h"
|
||||||
#include "llvm/Assembly/Writer.h"
|
#include "llvm/Assembly/Writer.h"
|
||||||
#include "llvm/Target/TargetData.h"
|
|
||||||
#include "Support/CommandLine.h"
|
#include "Support/CommandLine.h"
|
||||||
#include "Support/Statistic.h"
|
#include "Support/Statistic.h"
|
||||||
#include <math.h> // For fmod
|
#include <math.h> // For fmod
|
||||||
@ -23,11 +24,14 @@ using std::vector;
|
|||||||
using std::cout;
|
using std::cout;
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
|
|
||||||
|
Interpreter *TheEE = 0;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
Statistic<> NumDynamicInsts("lli", "Number of dynamic instructions executed");
|
Statistic<> NumDynamicInsts("lli", "Number of dynamic instructions executed");
|
||||||
|
|
||||||
cl::opt<bool>
|
cl::opt<bool>
|
||||||
QuietMode("quiet", cl::desc("Do not emit any non-program output"));
|
QuietMode("quiet", cl::desc("Do not emit any non-program output"),
|
||||||
|
cl::init(true));
|
||||||
|
|
||||||
cl::alias
|
cl::alias
|
||||||
QuietModeA("q", cl::desc("Alias for -quiet"), cl::aliasopt(QuietMode));
|
QuietModeA("q", cl::desc("Alias for -quiet"), cl::aliasopt(QuietMode));
|
||||||
@ -43,10 +47,8 @@ namespace {
|
|||||||
// Create a TargetData structure to handle memory addressing and size/alignment
|
// Create a TargetData structure to handle memory addressing and size/alignment
|
||||||
// computations
|
// computations
|
||||||
//
|
//
|
||||||
TargetData TD("lli Interpreter");
|
|
||||||
CachedWriter CW; // Object to accelerate printing of LLVM
|
CachedWriter CW; // Object to accelerate printing of LLVM
|
||||||
|
|
||||||
|
|
||||||
#ifdef PROFILE_STRUCTURE_FIELDS
|
#ifdef PROFILE_STRUCTURE_FIELDS
|
||||||
static cl::opt<bool>
|
static cl::opt<bool>
|
||||||
ProfileStructureFields("profilestructfields",
|
ProfileStructureFields("profilestructfields",
|
||||||
@ -87,48 +89,12 @@ static unsigned getOperandSlot(Value *V) {
|
|||||||
return SN->SlotNum;
|
return SN->SlotNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GET_CONST_VAL(TY, CLASS) \
|
|
||||||
case Type::TY##TyID: Result.TY##Val = cast<CLASS>(C)->getValue(); break
|
|
||||||
|
|
||||||
// Operations used by constant expr implementations...
|
// Operations used by constant expr implementations...
|
||||||
static GenericValue executeCastOperation(Value *Src, const Type *DestTy,
|
static GenericValue executeCastOperation(Value *Src, const Type *DestTy,
|
||||||
ExecutionContext &SF);
|
ExecutionContext &SF);
|
||||||
static GenericValue executeGEPOperation(Value *Src, User::op_iterator IdxBegin,
|
|
||||||
User::op_iterator IdxEnd,
|
|
||||||
ExecutionContext &SF);
|
|
||||||
static GenericValue executeAddInst(GenericValue Src1, GenericValue Src2,
|
static GenericValue executeAddInst(GenericValue Src1, GenericValue Src2,
|
||||||
const Type *Ty, ExecutionContext &SF);
|
const Type *Ty, ExecutionContext &SF);
|
||||||
|
|
||||||
static GenericValue getConstantValue(const Constant *C) {
|
|
||||||
GenericValue Result;
|
|
||||||
switch (C->getType()->getPrimitiveID()) {
|
|
||||||
GET_CONST_VAL(Bool , ConstantBool);
|
|
||||||
GET_CONST_VAL(UByte , ConstantUInt);
|
|
||||||
GET_CONST_VAL(SByte , ConstantSInt);
|
|
||||||
GET_CONST_VAL(UShort , ConstantUInt);
|
|
||||||
GET_CONST_VAL(Short , ConstantSInt);
|
|
||||||
GET_CONST_VAL(UInt , ConstantUInt);
|
|
||||||
GET_CONST_VAL(Int , ConstantSInt);
|
|
||||||
GET_CONST_VAL(ULong , ConstantUInt);
|
|
||||||
GET_CONST_VAL(Long , ConstantSInt);
|
|
||||||
GET_CONST_VAL(Float , ConstantFP);
|
|
||||||
GET_CONST_VAL(Double , ConstantFP);
|
|
||||||
case Type::PointerTyID:
|
|
||||||
if (isa<ConstantPointerNull>(C)) {
|
|
||||||
Result.PointerVal = 0;
|
|
||||||
} else if (const ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(C)){
|
|
||||||
GlobalAddress *Address =
|
|
||||||
(GlobalAddress*)CPR->getValue()->getOrCreateAnnotation(GlobalAddressAID);
|
|
||||||
Result.PointerVal = (PointerTy)Address->Ptr;
|
|
||||||
} else {
|
|
||||||
assert(0 && "Unknown constant pointer type!");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cout << "ERROR: Constant unimp for type: " << C->getType() << "\n";
|
|
||||||
}
|
|
||||||
return Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GenericValue getOperandValue(Value *V, ExecutionContext &SF) {
|
static GenericValue getOperandValue(Value *V, ExecutionContext &SF) {
|
||||||
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) {
|
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) {
|
||||||
@ -136,8 +102,8 @@ static GenericValue getOperandValue(Value *V, ExecutionContext &SF) {
|
|||||||
case Instruction::Cast:
|
case Instruction::Cast:
|
||||||
return executeCastOperation(CE->getOperand(0), CE->getType(), SF);
|
return executeCastOperation(CE->getOperand(0), CE->getType(), SF);
|
||||||
case Instruction::GetElementPtr:
|
case Instruction::GetElementPtr:
|
||||||
return executeGEPOperation(CE->getOperand(0), CE->op_begin()+1,
|
return TheEE->executeGEPOperation(CE->getOperand(0), CE->op_begin()+1,
|
||||||
CE->op_end(), SF);
|
CE->op_end(), SF);
|
||||||
case Instruction::Add:
|
case Instruction::Add:
|
||||||
return executeAddInst(getOperandValue(CE->getOperand(0), SF),
|
return executeAddInst(getOperandValue(CE->getOperand(0), SF),
|
||||||
getOperandValue(CE->getOperand(1), SF),
|
getOperandValue(CE->getOperand(1), SF),
|
||||||
@ -148,13 +114,9 @@ static GenericValue getOperandValue(Value *V, ExecutionContext &SF) {
|
|||||||
{ GenericValue V; return V; }
|
{ GenericValue V; return V; }
|
||||||
}
|
}
|
||||||
} else if (Constant *CPV = dyn_cast<Constant>(V)) {
|
} else if (Constant *CPV = dyn_cast<Constant>(V)) {
|
||||||
return getConstantValue(CPV);
|
return TheEE->getConstantValue(CPV);
|
||||||
} else if (GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
|
} else if (GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
|
||||||
GlobalAddress *Address =
|
return PTOGV(TheEE->getPointerToGlobal(GV));
|
||||||
(GlobalAddress*)GV->getOrCreateAnnotation(GlobalAddressAID);
|
|
||||||
GenericValue Result;
|
|
||||||
Result.PointerVal = (PointerTy)(GenericValue*)Address->Ptr;
|
|
||||||
return Result;
|
|
||||||
} else {
|
} else {
|
||||||
unsigned TyP = V->getType()->getUniqueID(); // TypePlane for value
|
unsigned TyP = V->getType()->getUniqueID(); // TypePlane for value
|
||||||
unsigned OpSlot = getOperandSlot(V);
|
unsigned OpSlot = getOperandSlot(V);
|
||||||
@ -201,85 +163,12 @@ static void SetValue(Value *V, GenericValue Val, ExecutionContext &SF) {
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
void Interpreter::initializeExecutionEngine() {
|
void Interpreter::initializeExecutionEngine() {
|
||||||
|
TheEE = this;
|
||||||
AnnotationManager::registerAnnotationFactory(MethodInfoAID,
|
AnnotationManager::registerAnnotationFactory(MethodInfoAID,
|
||||||
&MethodInfo::Create);
|
&MethodInfo::Create);
|
||||||
AnnotationManager::registerAnnotationFactory(GlobalAddressAID,
|
|
||||||
&GlobalAddress::Create);
|
|
||||||
initializeSignalHandlers();
|
initializeSignalHandlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void StoreValueToMemory(GenericValue Val, GenericValue *Ptr,
|
|
||||||
const Type *Ty);
|
|
||||||
|
|
||||||
// InitializeMemory - Recursive function to apply a Constant value into the
|
|
||||||
// specified memory location...
|
|
||||||
//
|
|
||||||
static void InitializeMemory(const Constant *Init, char *Addr) {
|
|
||||||
|
|
||||||
if (Init->getType()->isFirstClassType()) {
|
|
||||||
GenericValue Val = getConstantValue(Init);
|
|
||||||
StoreValueToMemory(Val, (GenericValue*)Addr, Init->getType());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (Init->getType()->getPrimitiveID()) {
|
|
||||||
case Type::ArrayTyID: {
|
|
||||||
const ConstantArray *CPA = cast<ConstantArray>(Init);
|
|
||||||
const vector<Use> &Val = CPA->getValues();
|
|
||||||
unsigned ElementSize =
|
|
||||||
TD.getTypeSize(cast<ArrayType>(CPA->getType())->getElementType());
|
|
||||||
for (unsigned i = 0; i < Val.size(); ++i)
|
|
||||||
InitializeMemory(cast<Constant>(Val[i].get()), Addr+i*ElementSize);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Type::StructTyID: {
|
|
||||||
const ConstantStruct *CPS = cast<ConstantStruct>(Init);
|
|
||||||
const StructLayout *SL=TD.getStructLayout(cast<StructType>(CPS->getType()));
|
|
||||||
const vector<Use> &Val = CPS->getValues();
|
|
||||||
for (unsigned i = 0; i < Val.size(); ++i)
|
|
||||||
InitializeMemory(cast<Constant>(Val[i].get()),
|
|
||||||
Addr+SL->MemberOffsets[i]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
CW << "Bad Type: " << Init->getType() << "\n";
|
|
||||||
assert(0 && "Unknown constant type to initialize memory with!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Annotation *GlobalAddress::Create(AnnotationID AID, const Annotable *O, void *){
|
|
||||||
assert(AID == GlobalAddressAID);
|
|
||||||
|
|
||||||
// This annotation will only be created on GlobalValue objects...
|
|
||||||
GlobalValue *GVal = cast<GlobalValue>((Value*)O);
|
|
||||||
|
|
||||||
if (isa<Function>(GVal)) {
|
|
||||||
// The GlobalAddress object for a function is just a pointer to function
|
|
||||||
// itself. Don't delete it when the annotation is gone though!
|
|
||||||
return new GlobalAddress(GVal, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the case of a global variable...
|
|
||||||
assert(isa<GlobalVariable>(GVal) &&
|
|
||||||
"Global value found that isn't a function or global variable!");
|
|
||||||
GlobalVariable *GV = cast<GlobalVariable>(GVal);
|
|
||||||
|
|
||||||
// First off, we must allocate space for the global variable to point at...
|
|
||||||
const Type *Ty = GV->getType()->getElementType(); // Type to be allocated
|
|
||||||
|
|
||||||
// Allocate enough memory to hold the type...
|
|
||||||
void *Addr = calloc(1, TD.getTypeSize(Ty));
|
|
||||||
assert(Addr != 0 && "Null pointer returned by malloc!");
|
|
||||||
|
|
||||||
// Initialize the memory if there is an initializer...
|
|
||||||
if (GV->hasInitializer())
|
|
||||||
InitializeMemory(GV->getInitializer(), (char*)Addr);
|
|
||||||
|
|
||||||
return new GlobalAddress(Addr, true); // Simply invoke the ctor
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Binary Instruction Implementations
|
// Binary Instruction Implementations
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
@ -760,8 +649,7 @@ void Interpreter::executeAllocInst(AllocationInst &I, ExecutionContext &SF) {
|
|||||||
// FIXME: Don't use CALLOC, use a tainted malloc.
|
// FIXME: Don't use CALLOC, use a tainted malloc.
|
||||||
void *Memory = calloc(NumElements, TD.getTypeSize(Ty));
|
void *Memory = calloc(NumElements, TD.getTypeSize(Ty));
|
||||||
|
|
||||||
GenericValue Result;
|
GenericValue Result = PTOGV(Memory);
|
||||||
Result.PointerVal = (PointerTy)Memory;
|
|
||||||
assert(Result.PointerVal != 0 && "Null pointer returned by malloc!");
|
assert(Result.PointerVal != 0 && "Null pointer returned by malloc!");
|
||||||
SetValue(&I, Result, SF);
|
SetValue(&I, Result, SF);
|
||||||
|
|
||||||
@ -773,15 +661,15 @@ static void executeFreeInst(FreeInst &I, ExecutionContext &SF) {
|
|||||||
assert(isa<PointerType>(I.getOperand(0)->getType()) && "Freeing nonptr?");
|
assert(isa<PointerType>(I.getOperand(0)->getType()) && "Freeing nonptr?");
|
||||||
GenericValue Value = getOperandValue(I.getOperand(0), SF);
|
GenericValue Value = getOperandValue(I.getOperand(0), SF);
|
||||||
// TODO: Check to make sure memory is allocated
|
// TODO: Check to make sure memory is allocated
|
||||||
free((void*)Value.PointerVal); // Free memory
|
free(GVTOP(Value)); // Free memory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// getElementOffset - The workhorse for getelementptr.
|
// getElementOffset - The workhorse for getelementptr.
|
||||||
//
|
//
|
||||||
static GenericValue executeGEPOperation(Value *Ptr, User::op_iterator I,
|
GenericValue Interpreter::executeGEPOperation(Value *Ptr, User::op_iterator I,
|
||||||
User::op_iterator E,
|
User::op_iterator E,
|
||||||
ExecutionContext &SF) {
|
ExecutionContext &SF) {
|
||||||
assert(isa<PointerType>(Ptr->getType()) &&
|
assert(isa<PointerType>(Ptr->getType()) &&
|
||||||
"Cannot getElementOffset of a nonpointer type!");
|
"Cannot getElementOffset of a nonpointer type!");
|
||||||
|
|
||||||
@ -834,13 +722,13 @@ static GenericValue executeGEPOperation(Value *Ptr, User::op_iterator I,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void executeGEPInst(GetElementPtrInst &I, ExecutionContext &SF) {
|
static void executeGEPInst(GetElementPtrInst &I, ExecutionContext &SF) {
|
||||||
SetValue(&I, executeGEPOperation(I.getPointerOperand(),
|
SetValue(&I, TheEE->executeGEPOperation(I.getPointerOperand(),
|
||||||
I.idx_begin(), I.idx_end(), SF), SF);
|
I.idx_begin(), I.idx_end(), SF), SF);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void executeLoadInst(LoadInst &I, ExecutionContext &SF) {
|
void Interpreter::executeLoadInst(LoadInst &I, ExecutionContext &SF) {
|
||||||
GenericValue SRC = getOperandValue(I.getPointerOperand(), SF);
|
GenericValue SRC = getOperandValue(I.getPointerOperand(), SF);
|
||||||
GenericValue *Ptr = (GenericValue*)SRC.PointerVal;
|
GenericValue *Ptr = (GenericValue*)GVTOP(SRC);
|
||||||
GenericValue Result;
|
GenericValue Result;
|
||||||
|
|
||||||
if (TD.isLittleEndian()) {
|
if (TD.isLittleEndian()) {
|
||||||
@ -910,102 +798,14 @@ static void executeLoadInst(LoadInst &I, ExecutionContext &SF) {
|
|||||||
SetValue(&I, Result, SF);
|
SetValue(&I, Result, SF);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void StoreValueToMemory(GenericValue Val, GenericValue *Ptr,
|
void Interpreter::executeStoreInst(StoreInst &I, ExecutionContext &SF) {
|
||||||
const Type *Ty) {
|
|
||||||
if (TD.isLittleEndian()) {
|
|
||||||
switch (Ty->getPrimitiveID()) {
|
|
||||||
case Type::BoolTyID:
|
|
||||||
case Type::UByteTyID:
|
|
||||||
case Type::SByteTyID: Ptr->Untyped[0] = Val.UByteVal; break;
|
|
||||||
case Type::UShortTyID:
|
|
||||||
case Type::ShortTyID: Ptr->Untyped[0] = Val.UShortVal & 255;
|
|
||||||
Ptr->Untyped[1] = (Val.UShortVal >> 8) & 255;
|
|
||||||
break;
|
|
||||||
case Type::FloatTyID:
|
|
||||||
case Type::UIntTyID:
|
|
||||||
case Type::IntTyID: Ptr->Untyped[0] = Val.UIntVal & 255;
|
|
||||||
Ptr->Untyped[1] = (Val.UIntVal >> 8) & 255;
|
|
||||||
Ptr->Untyped[2] = (Val.UIntVal >> 16) & 255;
|
|
||||||
Ptr->Untyped[3] = (Val.UIntVal >> 24) & 255;
|
|
||||||
break;
|
|
||||||
case Type::DoubleTyID:
|
|
||||||
case Type::ULongTyID:
|
|
||||||
case Type::LongTyID:
|
|
||||||
case Type::PointerTyID: Ptr->Untyped[0] = Val.ULongVal & 255;
|
|
||||||
Ptr->Untyped[1] = (Val.ULongVal >> 8) & 255;
|
|
||||||
Ptr->Untyped[2] = (Val.ULongVal >> 16) & 255;
|
|
||||||
Ptr->Untyped[3] = (Val.ULongVal >> 24) & 255;
|
|
||||||
Ptr->Untyped[4] = (Val.ULongVal >> 32) & 255;
|
|
||||||
Ptr->Untyped[5] = (Val.ULongVal >> 40) & 255;
|
|
||||||
Ptr->Untyped[6] = (Val.ULongVal >> 48) & 255;
|
|
||||||
Ptr->Untyped[7] = (Val.ULongVal >> 56) & 255;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cout << "Cannot store value of type " << Ty << "!\n";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (Ty->getPrimitiveID()) {
|
|
||||||
case Type::BoolTyID:
|
|
||||||
case Type::UByteTyID:
|
|
||||||
case Type::SByteTyID: Ptr->Untyped[0] = Val.UByteVal; break;
|
|
||||||
case Type::UShortTyID:
|
|
||||||
case Type::ShortTyID: Ptr->Untyped[1] = Val.UShortVal & 255;
|
|
||||||
Ptr->Untyped[0] = (Val.UShortVal >> 8) & 255;
|
|
||||||
break;
|
|
||||||
case Type::FloatTyID:
|
|
||||||
case Type::UIntTyID:
|
|
||||||
case Type::IntTyID: Ptr->Untyped[3] = Val.UIntVal & 255;
|
|
||||||
Ptr->Untyped[2] = (Val.UIntVal >> 8) & 255;
|
|
||||||
Ptr->Untyped[1] = (Val.UIntVal >> 16) & 255;
|
|
||||||
Ptr->Untyped[0] = (Val.UIntVal >> 24) & 255;
|
|
||||||
break;
|
|
||||||
case Type::DoubleTyID:
|
|
||||||
case Type::ULongTyID:
|
|
||||||
case Type::LongTyID:
|
|
||||||
case Type::PointerTyID: Ptr->Untyped[7] = Val.ULongVal & 255;
|
|
||||||
Ptr->Untyped[6] = (Val.ULongVal >> 8) & 255;
|
|
||||||
Ptr->Untyped[5] = (Val.ULongVal >> 16) & 255;
|
|
||||||
Ptr->Untyped[4] = (Val.ULongVal >> 24) & 255;
|
|
||||||
Ptr->Untyped[3] = (Val.ULongVal >> 32) & 255;
|
|
||||||
Ptr->Untyped[2] = (Val.ULongVal >> 40) & 255;
|
|
||||||
Ptr->Untyped[1] = (Val.ULongVal >> 48) & 255;
|
|
||||||
Ptr->Untyped[0] = (Val.ULongVal >> 56) & 255;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cout << "Cannot store value of type " << Ty << "!\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void executeStoreInst(StoreInst &I, ExecutionContext &SF) {
|
|
||||||
GenericValue Val = getOperandValue(I.getOperand(0), SF);
|
GenericValue Val = getOperandValue(I.getOperand(0), SF);
|
||||||
GenericValue SRC = getOperandValue(I.getPointerOperand(), SF);
|
GenericValue SRC = getOperandValue(I.getPointerOperand(), SF);
|
||||||
StoreValueToMemory(Val, (GenericValue *)SRC.PointerVal,
|
StoreValueToMemory(Val, (GenericValue *)GVTOP(SRC),
|
||||||
I.getOperand(0)->getType());
|
I.getOperand(0)->getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GenericValue Interpreter::CreateArgv(const std::vector<std::string> &InputArgv){
|
|
||||||
// Pointers are 64 bits...
|
|
||||||
PointerTy *Result = new PointerTy[InputArgv.size()+1]; // 64 bit assumption
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < InputArgv.size(); ++i) {
|
|
||||||
unsigned Size = InputArgv[i].size()+1;
|
|
||||||
char *Dest = new char[Size];
|
|
||||||
copy(InputArgv[i].begin(), InputArgv[i].end(), Dest);
|
|
||||||
Dest[Size-1] = 0;
|
|
||||||
|
|
||||||
GenericValue GV; GV.PointerVal = (PointerTy)Dest;
|
|
||||||
// Endian safe: Result[i] = (PointerTy)Dest;
|
|
||||||
StoreValueToMemory(GV, (GenericValue*)(Result+i),
|
|
||||||
Type::LongTy); // 64 bit assumption
|
|
||||||
}
|
|
||||||
|
|
||||||
Result[InputArgv.size()] = 0;
|
|
||||||
GenericValue GV; GV.PointerVal = (PointerTy)Result;
|
|
||||||
return GV;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Miscellaneous Instruction Implementations
|
// Miscellaneous Instruction Implementations
|
||||||
@ -1022,7 +822,7 @@ void Interpreter::executeCallInst(CallInst &I, ExecutionContext &SF) {
|
|||||||
// and treat it as a function pointer.
|
// and treat it as a function pointer.
|
||||||
GenericValue SRC = getOperandValue(I.getCalledValue(), SF);
|
GenericValue SRC = getOperandValue(I.getCalledValue(), SF);
|
||||||
|
|
||||||
callMethod((Function*)SRC.PointerVal, ArgVals);
|
callMethod((Function*)GVTOP(SRC), ArgVals);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void executePHINode(PHINode &I, ExecutionContext &SF) {
|
static void executePHINode(PHINode &I, ExecutionContext &SF) {
|
||||||
@ -1433,7 +1233,7 @@ void Interpreter::printValue(const Type *Ty, GenericValue V) {
|
|||||||
case Type::ULongTyID: cout << (unsigned long)V.ULongVal; break;
|
case Type::ULongTyID: cout << (unsigned long)V.ULongVal; break;
|
||||||
case Type::FloatTyID: cout << V.FloatVal; break;
|
case Type::FloatTyID: cout << V.FloatVal; break;
|
||||||
case Type::DoubleTyID: cout << V.DoubleVal; break;
|
case Type::DoubleTyID: cout << V.DoubleVal; break;
|
||||||
case Type::PointerTyID:cout << (void*)V.PointerVal; break;
|
case Type::PointerTyID:cout << (void*)GVTOP(V); break;
|
||||||
default:
|
default:
|
||||||
cout << "- Don't know how to print value of this type!";
|
cout << "- Don't know how to print value of this type!";
|
||||||
break;
|
break;
|
||||||
|
@ -90,32 +90,4 @@ static AnnotationID BreakpointAID(
|
|||||||
// Just use an Annotation directly, Breakpoint is currently just a marker
|
// Just use an Annotation directly, Breakpoint is currently just a marker
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// Support for the GlobalAddress annotation
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
// This annotation (attached only to GlobalValue objects) is used to hold the
|
|
||||||
// address of the chunk of memory that represents a global value. For
|
|
||||||
// Functions, this pointer is the Function object pointer that represents it.
|
|
||||||
// For global variables, this is the dynamically allocated (and potentially
|
|
||||||
// initialized) chunk of memory for the global. This annotation is created on
|
|
||||||
// demand.
|
|
||||||
//
|
|
||||||
static AnnotationID GlobalAddressAID(
|
|
||||||
AnnotationManager::getID("Interpreter::GlobalAddress"));
|
|
||||||
|
|
||||||
struct GlobalAddress : public Annotation {
|
|
||||||
void *Ptr; // The pointer itself
|
|
||||||
bool Delete; // Should I delete them memory on destruction?
|
|
||||||
|
|
||||||
GlobalAddress(void *ptr, bool d) : Annotation(GlobalAddressAID), Ptr(ptr),
|
|
||||||
Delete(d) {}
|
|
||||||
~GlobalAddress() { if (Delete) free(Ptr); }
|
|
||||||
|
|
||||||
// Create - Factory function to allow GlobalAddress annotations to be
|
|
||||||
// created on demand.
|
|
||||||
//
|
|
||||||
static Annotation *Create(AnnotationID AID, const Annotable *O, void *);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "Interpreter.h"
|
#include "Interpreter.h"
|
||||||
#include "ExecutionAnnotations.h"
|
#include "ExecutionAnnotations.h"
|
||||||
|
#include "llvm/Module.h"
|
||||||
#include "llvm/DerivedTypes.h"
|
#include "llvm/DerivedTypes.h"
|
||||||
#include "llvm/SymbolTable.h"
|
#include "llvm/SymbolTable.h"
|
||||||
#include "llvm/Target/TargetData.h"
|
#include "llvm/Target/TargetData.h"
|
||||||
@ -23,8 +24,6 @@
|
|||||||
using std::vector;
|
using std::vector;
|
||||||
using std::cout;
|
using std::cout;
|
||||||
|
|
||||||
extern TargetData TD;
|
|
||||||
|
|
||||||
typedef GenericValue (*ExFunc)(FunctionType *, const vector<GenericValue> &);
|
typedef GenericValue (*ExFunc)(FunctionType *, const vector<GenericValue> &);
|
||||||
static std::map<const Function *, ExFunc> Functions;
|
static std::map<const Function *, ExFunc> Functions;
|
||||||
static std::map<std::string, ExFunc> FuncNames;
|
static std::map<std::string, ExFunc> FuncNames;
|
||||||
@ -440,8 +439,8 @@ static FILE *getFILE(PointerTy Ptr) {
|
|||||||
static PointerTy IOBBase = 0;
|
static PointerTy IOBBase = 0;
|
||||||
static unsigned FILESize;
|
static unsigned FILESize;
|
||||||
|
|
||||||
if (LastMod != TheInterpreter->getModule()) { // Module change or initialize?
|
if (LastMod != &TheInterpreter->getModule()) { // Module change or initialize?
|
||||||
Module *M = LastMod = TheInterpreter->getModule();
|
Module *M = LastMod = &TheInterpreter->getModule();
|
||||||
|
|
||||||
// Check to see if the currently loaded module contains an __iob symbol...
|
// Check to see if the currently loaded module contains an __iob symbol...
|
||||||
GlobalVariable *IOB = 0;
|
GlobalVariable *IOB = 0;
|
||||||
@ -456,6 +455,7 @@ static FILE *getFILE(PointerTy Ptr) {
|
|||||||
if (IOB) break;
|
if (IOB) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0 /// FIXME! __iob support for LLI
|
||||||
// If we found an __iob symbol now, find out what the actual address it's
|
// If we found an __iob symbol now, find out what the actual address it's
|
||||||
// held in is...
|
// held in is...
|
||||||
if (IOB) {
|
if (IOB) {
|
||||||
@ -472,6 +472,7 @@ static FILE *getFILE(PointerTy Ptr) {
|
|||||||
else
|
else
|
||||||
FILESize = 16*8; // Default size
|
FILESize = 16*8; // Default size
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if this is a reference to __iob...
|
// Check to see if this is a reference to __iob...
|
||||||
|
@ -10,36 +10,23 @@
|
|||||||
// Uncomment this line to enable profiling of structure field accesses.
|
// Uncomment this line to enable profiling of structure field accesses.
|
||||||
//#define PROFILE_STRUCTURE_FIELDS 1
|
//#define PROFILE_STRUCTURE_FIELDS 1
|
||||||
|
|
||||||
#include "llvm/Module.h"
|
#include "../ExecutionEngine.h"
|
||||||
#include "Support/DataTypes.h"
|
#include "Support/DataTypes.h"
|
||||||
#include "llvm/Assembly/CachedWriter.h"
|
#include "llvm/Assembly/CachedWriter.h"
|
||||||
|
#include "llvm/Target/TargetData.h"
|
||||||
|
#include "llvm/BasicBlock.h"
|
||||||
|
#include "../GenericValue.h"
|
||||||
|
|
||||||
extern CachedWriter CW; // Object to accellerate printing of LLVM
|
extern CachedWriter CW; // Object to accelerate printing of LLVM
|
||||||
|
|
||||||
struct MethodInfo; // Defined in ExecutionAnnotations.h
|
struct MethodInfo; // Defined in ExecutionAnnotations.h
|
||||||
class CallInst;
|
class CallInst;
|
||||||
class ReturnInst;
|
class ReturnInst;
|
||||||
class BranchInst;
|
class BranchInst;
|
||||||
|
class LoadInst;
|
||||||
|
class StoreInst;
|
||||||
class AllocationInst;
|
class AllocationInst;
|
||||||
|
|
||||||
typedef uint64_t PointerTy;
|
|
||||||
|
|
||||||
union GenericValue {
|
|
||||||
bool BoolVal;
|
|
||||||
unsigned char UByteVal;
|
|
||||||
signed char SByteVal;
|
|
||||||
unsigned short UShortVal;
|
|
||||||
signed short ShortVal;
|
|
||||||
unsigned int UIntVal;
|
|
||||||
signed int IntVal;
|
|
||||||
uint64_t ULongVal;
|
|
||||||
int64_t LongVal;
|
|
||||||
double DoubleVal;
|
|
||||||
float FloatVal;
|
|
||||||
PointerTy PointerVal;
|
|
||||||
unsigned char Untyped[8];
|
|
||||||
};
|
|
||||||
|
|
||||||
// AllocaHolder - Object to track all of the blocks of memory allocated by
|
// AllocaHolder - Object to track all of the blocks of memory allocated by
|
||||||
// alloca. When the function returns, this object is poped off the execution
|
// alloca. When the function returns, this object is poped off the execution
|
||||||
// stack, which causes the dtor to be run, which frees all the alloca'd memory.
|
// stack, which causes the dtor to be run, which frees all the alloca'd memory.
|
||||||
@ -90,25 +77,31 @@ struct ExecutionContext {
|
|||||||
|
|
||||||
// Interpreter - This class represents the entirety of the interpreter.
|
// Interpreter - This class represents the entirety of the interpreter.
|
||||||
//
|
//
|
||||||
class Interpreter {
|
class Interpreter : public ExecutionEngine {
|
||||||
Module *CurMod; // The current Module being executed (0 if none)
|
|
||||||
int ExitCode; // The exit code to be returned by the lli util
|
int ExitCode; // The exit code to be returned by the lli util
|
||||||
|
bool Debug; // Debug mode enabled?
|
||||||
bool Profile; // Profiling enabled?
|
bool Profile; // Profiling enabled?
|
||||||
bool Trace; // Tracing enabled?
|
bool Trace; // Tracing enabled?
|
||||||
int CurFrame; // The current stack frame being inspected
|
int CurFrame; // The current stack frame being inspected
|
||||||
|
TargetData TD;
|
||||||
|
|
||||||
// The runtime stack of executing code. The top of the stack is the current
|
// The runtime stack of executing code. The top of the stack is the current
|
||||||
// function record.
|
// function record.
|
||||||
std::vector<ExecutionContext> ECStack;
|
std::vector<ExecutionContext> ECStack;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Interpreter();
|
Interpreter(Module *M, unsigned Config, bool DebugMode, bool TraceMode);
|
||||||
inline ~Interpreter() { CW.setModule(0); delete CurMod; }
|
inline ~Interpreter() { CW.setModule(0); }
|
||||||
|
|
||||||
// getExitCode - return the code that should be the exit code for the lli
|
// getExitCode - return the code that should be the exit code for the lli
|
||||||
// utility.
|
// utility.
|
||||||
inline int getExitCode() const { return ExitCode; }
|
inline int getExitCode() const { return ExitCode; }
|
||||||
inline Module *getModule() const { return CurMod; }
|
|
||||||
|
/// run - Start execution with the specified function and arguments.
|
||||||
|
///
|
||||||
|
virtual int run(const std::string &FnName,
|
||||||
|
const std::vector<std::string> &Args);
|
||||||
|
|
||||||
|
|
||||||
// enableProfiling() - Turn profiling on, clear stats?
|
// enableProfiling() - Turn profiling on, clear stats?
|
||||||
void enableProfiling() { Profile = true; }
|
void enableProfiling() { Profile = true; }
|
||||||
@ -117,8 +110,6 @@ public:
|
|||||||
void handleUserInput();
|
void handleUserInput();
|
||||||
|
|
||||||
// User Interation Methods...
|
// User Interation Methods...
|
||||||
void loadModule(const std::string &Filename);
|
|
||||||
bool flushModule();
|
|
||||||
bool callMethod(const std::string &Name); // return true on failure
|
bool callMethod(const std::string &Name); // return true on failure
|
||||||
void setBreakpoint(const std::string &Name);
|
void setBreakpoint(const std::string &Name);
|
||||||
void infoValue(const std::string &Name);
|
void infoValue(const std::string &Name);
|
||||||
@ -128,7 +119,6 @@ public:
|
|||||||
|
|
||||||
bool callMainMethod(const std::string &MainName,
|
bool callMainMethod(const std::string &MainName,
|
||||||
const std::vector<std::string> &InputFilename);
|
const std::vector<std::string> &InputFilename);
|
||||||
GenericValue CreateArgv(const std::vector<std::string> &InputArgv);
|
|
||||||
|
|
||||||
void list(); // Do the 'list' command
|
void list(); // Do the 'list' command
|
||||||
void printStackTrace(); // Do the 'backtrace' command
|
void printStackTrace(); // Do the 'backtrace' command
|
||||||
@ -161,7 +151,17 @@ public:
|
|||||||
//
|
//
|
||||||
inline bool isStopped() const { return !ECStack.empty(); }
|
inline bool isStopped() const { return !ECStack.empty(); }
|
||||||
|
|
||||||
|
//FIXME: private:
|
||||||
|
public:
|
||||||
|
GenericValue executeGEPOperation(Value *Ptr, User::op_iterator I,
|
||||||
|
User::op_iterator E, ExecutionContext &SF);
|
||||||
|
void executeLoadInst(LoadInst &I, ExecutionContext &SF);
|
||||||
|
void executeStoreInst(StoreInst &I, ExecutionContext &SF);
|
||||||
|
|
||||||
|
|
||||||
private: // Helper functions
|
private: // Helper functions
|
||||||
|
void *getPointerToFunction(const Function *F) { return (void*)F; }
|
||||||
|
|
||||||
// getCurrentExecutablePath() - Return the directory that the lli executable
|
// getCurrentExecutablePath() - Return the directory that the lli executable
|
||||||
// lives in.
|
// lives in.
|
||||||
//
|
//
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "Interpreter.h"
|
#include "Interpreter.h"
|
||||||
#include "llvm/SymbolTable.h"
|
#include "llvm/SymbolTable.h"
|
||||||
#include "llvm/Assembly/Writer.h"
|
#include "llvm/Assembly/Writer.h"
|
||||||
|
#include "llvm/Module.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
using std::cout;
|
using std::cout;
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ std::vector<Value*> Interpreter::LookupMatchingNames(const std::string &Name) {
|
|||||||
Function *CurMeth = getCurrentMethod();
|
Function *CurMeth = getCurrentMethod();
|
||||||
|
|
||||||
if (CurMeth) ::LookupMatchingNames(Name, CurMeth->getSymbolTable(), Results);
|
if (CurMeth) ::LookupMatchingNames(Name, CurMeth->getSymbolTable(), Results);
|
||||||
if (CurMod ) ::LookupMatchingNames(Name, CurMod ->getSymbolTable(), Results);
|
::LookupMatchingNames(Name, getModule().getSymbolTable(), Results);
|
||||||
return Results;
|
return Results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "Interpreter.h"
|
#include "Interpreter.h"
|
||||||
#include "llvm/Bytecode/Reader.h"
|
#include "llvm/Bytecode/Reader.h"
|
||||||
#include "llvm/DerivedTypes.h"
|
#include "llvm/DerivedTypes.h"
|
||||||
|
#include "llvm/Function.h"
|
||||||
#include "llvm/Transforms/Utils/Linker.h"
|
#include "llvm/Transforms/Utils/Linker.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
using std::string;
|
using std::string;
|
||||||
@ -18,8 +19,8 @@ enum CommandID {
|
|||||||
Print, Info, List, StackTrace, Up, Down, // Inspection
|
Print, Info, List, StackTrace, Up, Down, // Inspection
|
||||||
Next, Step, Run, Finish, Call, // Control flow changes
|
Next, Step, Run, Finish, Call, // Control flow changes
|
||||||
Break, Watch, // Debugging
|
Break, Watch, // Debugging
|
||||||
Load, Flush,
|
Flush,
|
||||||
TraceOpt, ProfileOpt // Toggle features
|
TraceOpt, // Toggle features
|
||||||
};
|
};
|
||||||
|
|
||||||
// CommandTable - Build a lookup table for the commands available to the user...
|
// CommandTable - Build a lookup table for the commands available to the user...
|
||||||
@ -53,11 +54,9 @@ static struct CommandTableElement {
|
|||||||
{ "break" , Break }, { "b", Break },
|
{ "break" , Break }, { "b", Break },
|
||||||
{ "watch" , Watch },
|
{ "watch" , Watch },
|
||||||
|
|
||||||
{ "load" , Load },
|
|
||||||
{ "flush" , Flush },
|
{ "flush" , Flush },
|
||||||
|
|
||||||
{ "trace" , TraceOpt },
|
{ "trace" , TraceOpt },
|
||||||
{ "profile" , ProfileOpt },
|
|
||||||
};
|
};
|
||||||
static CommandTableElement *CommandTableEnd =
|
static CommandTableElement *CommandTableEnd =
|
||||||
CommandTable+sizeof(CommandTable)/sizeof(CommandTable[0]);
|
CommandTable+sizeof(CommandTable)/sizeof(CommandTable[0]);
|
||||||
@ -90,11 +89,6 @@ void Interpreter::handleUserInput() {
|
|||||||
|
|
||||||
switch (E->CID) {
|
switch (E->CID) {
|
||||||
case Quit: UserQuit = true; break;
|
case Quit: UserQuit = true; break;
|
||||||
case Load:
|
|
||||||
cin >> Command;
|
|
||||||
loadModule(Command);
|
|
||||||
break;
|
|
||||||
case Flush: flushModule(); break;
|
|
||||||
case Print:
|
case Print:
|
||||||
cin >> Command;
|
cin >> Command;
|
||||||
print(Command);
|
print(Command);
|
||||||
@ -132,11 +126,6 @@ void Interpreter::handleUserInput() {
|
|||||||
cout << "Tracing " << (Trace ? "enabled\n" : "disabled\n");
|
cout << "Tracing " << (Trace ? "enabled\n" : "disabled\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ProfileOpt:
|
|
||||||
Profile = !Profile;
|
|
||||||
cout << "Profiling " << (Trace ? "enabled\n" : "disabled\n");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cout << "Command '" << Command << "' unimplemented!\n";
|
cout << "Command '" << Command << "' unimplemented!\n";
|
||||||
break;
|
break;
|
||||||
@ -145,61 +134,6 @@ void Interpreter::handleUserInput() {
|
|||||||
} while (!UserQuit);
|
} while (!UserQuit);
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// loadModule - Load a new module to execute...
|
|
||||||
//
|
|
||||||
void Interpreter::loadModule(const string &Filename) {
|
|
||||||
string ErrorMsg;
|
|
||||||
if (CurMod && !flushModule()) return; // Kill current execution
|
|
||||||
|
|
||||||
CurMod = ParseBytecodeFile(Filename, &ErrorMsg);
|
|
||||||
if (CurMod == 0) {
|
|
||||||
cout << "Error parsing '" << Filename << "': No module loaded: "
|
|
||||||
<< ErrorMsg << "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CW.setModule(CurMod); // Update Writer
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
string RuntimeLib = getCurrentExecutablePath();
|
|
||||||
if (!RuntimeLib.empty()) RuntimeLib += "/";
|
|
||||||
RuntimeLib += "RuntimeLib.bc";
|
|
||||||
|
|
||||||
if (Module *SupportLib = ParseBytecodeFile(RuntimeLib, &ErrorMsg)) {
|
|
||||||
if (LinkModules(CurMod, SupportLib, &ErrorMsg))
|
|
||||||
std::cerr << "Error Linking runtime library into current module: "
|
|
||||||
<< ErrorMsg << "\n";
|
|
||||||
} else {
|
|
||||||
std::cerr << "Error loading runtime library '"+RuntimeLib+"': "
|
|
||||||
<< ErrorMsg << "\n";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
// flushModule - Return true if the current program has been unloaded.
|
|
||||||
//
|
|
||||||
bool Interpreter::flushModule() {
|
|
||||||
if (CurMod == 0) {
|
|
||||||
cout << "Error flushing: No module loaded!\n";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ECStack.empty()) {
|
|
||||||
// TODO: if use is not sure, return false
|
|
||||||
cout << "Killing current execution!\n";
|
|
||||||
ECStack.clear();
|
|
||||||
CurFrame = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
CW.setModule(0);
|
|
||||||
delete CurMod;
|
|
||||||
CurMod = 0;
|
|
||||||
ExitCode = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// setBreakpoint - Enable a breakpoint at the specified location
|
// setBreakpoint - Enable a breakpoint at the specified location
|
||||||
//
|
//
|
||||||
@ -272,7 +206,7 @@ bool Interpreter::callMainMethod(const string &Name,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Args.push_back(CreateArgv(InputArgv));
|
Args.push_back(PTOGV(CreateArgv(InputArgv)));
|
||||||
}
|
}
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
LEVEL = ../..
|
LEVEL = ../..
|
||||||
TOOLNAME = lli
|
TOOLNAME = lli
|
||||||
USEDLIBS = bcreader vmcore analysis.a support.a target.a transforms.a
|
PARALLEL_DIRS = Interpreter JIT
|
||||||
|
|
||||||
|
JITLIBS = lli-jit codegen x86 scalaropts.a
|
||||||
|
USEDLIBS = lli-interpreter $(JITLIBS) bcreader vmcore analysis.a support.a target.a
|
||||||
|
#transforms.a
|
||||||
|
|
||||||
# Have gcc tell the linker to export symbols from the program so that
|
# Have gcc tell the linker to export symbols from the program so that
|
||||||
# dynamically loaded modules can be linked against them.
|
# dynamically loaded modules can be linked against them.
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
LEVEL = ../..
|
LEVEL = ../..
|
||||||
TOOLNAME = lli
|
TOOLNAME = lli
|
||||||
USEDLIBS = bcreader vmcore analysis.a support.a target.a transforms.a
|
PARALLEL_DIRS = Interpreter JIT
|
||||||
|
|
||||||
|
JITLIBS = lli-jit codegen x86 scalaropts.a
|
||||||
|
USEDLIBS = lli-interpreter $(JITLIBS) bcreader vmcore analysis.a support.a target.a
|
||||||
|
#transforms.a
|
||||||
|
|
||||||
# Have gcc tell the linker to export symbols from the program so that
|
# Have gcc tell the linker to export symbols from the program so that
|
||||||
# dynamically loaded modules can be linked against them.
|
# dynamically loaded modules can be linked against them.
|
||||||
|
@ -1,85 +1,101 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===- lli.cpp - LLVM Interpreter / Dynamic compiler ----------------------===//
|
||||||
// LLVM INTERPRETER/DEBUGGER/PROFILER UTILITY
|
|
||||||
//
|
//
|
||||||
// This utility is an interactive frontend to almost all other LLVM
|
// This utility provides a way to execute LLVM bytecode without static
|
||||||
// functionality. It may be used as an interpreter to run code, a debugger to
|
// compilation. This consists of a very simple and slow (but portable)
|
||||||
// find problems, or a profiler to analyze execution frequencies.
|
// interpreter, along with capability for system specific dynamic compilers. At
|
||||||
|
// runtime, the fastest (stable) execution engine is selected to run the
|
||||||
|
// program. This means the JIT compiler for the current platform if it's
|
||||||
|
// available.
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "Interpreter.h"
|
#include "ExecutionEngine.h"
|
||||||
#include "Support/CommandLine.h"
|
#include "Support/CommandLine.h"
|
||||||
|
#include "llvm/Bytecode/Reader.h"
|
||||||
|
#include "llvm/Module.h"
|
||||||
|
#include "llvm/Target/TargetMachineImpls.h"
|
||||||
|
|
||||||
static cl::opt<std::string>
|
namespace {
|
||||||
InputFile(cl::desc("<input bytecode>"), cl::Positional, cl::init("-"));
|
cl::opt<std::string>
|
||||||
|
InputFile(cl::desc("<input bytecode>"), cl::Positional, cl::init("-"));
|
||||||
|
|
||||||
static cl::list<std::string>
|
cl::list<std::string>
|
||||||
InputArgv(cl::ConsumeAfter, cl::desc("<program arguments>..."));
|
InputArgv(cl::ConsumeAfter, cl::desc("<program arguments>..."));
|
||||||
|
|
||||||
static cl::opt<std::string>
|
cl::opt<std::string>
|
||||||
MainFunction ("f", cl::desc("Function to execute"), cl::init("main"),
|
MainFunction ("f", cl::desc("Function to execute"), cl::init("main"),
|
||||||
cl::value_desc("function name"));
|
cl::value_desc("function name"));
|
||||||
|
|
||||||
static cl::opt<bool>
|
cl::opt<bool> DebugMode("d", cl::desc("Start program in debugger"));
|
||||||
DebugMode("d", cl::desc("Start program in debugger"));
|
|
||||||
|
|
||||||
static cl::opt<bool>
|
cl::opt<bool> TraceMode("trace", cl::desc("Enable Tracing"));
|
||||||
TraceMode("trace", cl::desc("Enable Tracing"));
|
|
||||||
|
|
||||||
static cl::opt<bool>
|
|
||||||
ProfileMode("profile", cl::desc("Enable Profiling [unimp]"));
|
|
||||||
|
|
||||||
|
cl::opt<bool> ForceInterpreter("force-interpreter",
|
||||||
|
cl::desc("Force interpretation: disable JIT"),
|
||||||
|
cl::init(true));
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Interpreter ctor - Initialize stuff
|
// ExecutionEngine Class Implementation
|
||||||
//
|
//
|
||||||
Interpreter::Interpreter() : ExitCode(0), Profile(ProfileMode),
|
|
||||||
Trace(TraceMode), CurFrame(-1) {
|
|
||||||
CurMod = 0;
|
|
||||||
loadModule(InputFile);
|
|
||||||
|
|
||||||
// Initialize the "backend"
|
ExecutionEngine::~ExecutionEngine() {
|
||||||
initializeExecutionEngine();
|
delete &CurMod;
|
||||||
initializeExternalMethods();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// main Driver function
|
// main Driver function
|
||||||
//
|
//
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
cl::ParseCommandLineOptions(argc, argv, " llvm interpreter\n");
|
cl::ParseCommandLineOptions(argc, argv,
|
||||||
|
" llvm interpreter & dynamic compiler\n");
|
||||||
|
|
||||||
// Add the module name to the start of the argv vector...
|
// Load the bytecode...
|
||||||
//
|
string ErrorMsg;
|
||||||
InputArgv.insert(InputArgv.begin(), InputFile);
|
Module *M = ParseBytecodeFile(InputFile, &ErrorMsg);
|
||||||
|
if (M == 0) {
|
||||||
// Create the interpreter...
|
cout << "Error parsing '" << InputFile << "': "
|
||||||
Interpreter I;
|
<< ErrorMsg << "\n";
|
||||||
|
exit(1);
|
||||||
// Handle alternate names of the program. If started as llp, enable profiling
|
|
||||||
// if started as ldb, enable debugging...
|
|
||||||
//
|
|
||||||
if (argv[0] == "ldb") // TODO: Obviously incorrect, but you get the idea
|
|
||||||
DebugMode = true;
|
|
||||||
else if (argv[0] == "llp")
|
|
||||||
ProfileMode = true;
|
|
||||||
|
|
||||||
// If running with the profiler, enable it now...
|
|
||||||
if (ProfileMode) I.enableProfiling();
|
|
||||||
if (TraceMode) I.enableTracing();
|
|
||||||
|
|
||||||
// Start interpreter into the main function...
|
|
||||||
//
|
|
||||||
if (!I.callMainMethod(MainFunction, InputArgv) && !DebugMode) {
|
|
||||||
// If not in debug mode and if the call succeeded, run the code now...
|
|
||||||
I.run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If debug mode, allow the user to interact... also, if the user pressed
|
#if 0
|
||||||
// ctrl-c or execution hit an error, enter the event loop...
|
// Link in the runtime library for LLI...
|
||||||
if (DebugMode || I.isStopped())
|
string RuntimeLib = getCurrentExecutablePath();
|
||||||
I.handleUserInput();
|
if (!RuntimeLib.empty()) RuntimeLib += "/";
|
||||||
|
RuntimeLib += "RuntimeLib.bc";
|
||||||
|
|
||||||
// Return the status code of the program executed...
|
if (Module *SupportLib = ParseBytecodeFile(RuntimeLib, &ErrorMsg)) {
|
||||||
return I.getExitCode();
|
if (LinkModules(M, SupportLib, &ErrorMsg))
|
||||||
|
std::cerr << "Error Linking runtime library into current module: "
|
||||||
|
<< ErrorMsg << "\n";
|
||||||
|
} else {
|
||||||
|
std::cerr << "Error loading runtime library '"+RuntimeLib+"': "
|
||||||
|
<< ErrorMsg << "\n";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// FIXME: This should look at the PointerSize and endianness of the bytecode
|
||||||
|
// file to determine the endianness and pointer size of target machine to use.
|
||||||
|
unsigned Config = TM::PtrSize64 | TM::BigEndian;
|
||||||
|
|
||||||
|
ExecutionEngine *EE = 0;
|
||||||
|
|
||||||
|
// If there is nothing that is forcing us to use the interpreter, make a JIT.
|
||||||
|
if (!ForceInterpreter && !DebugMode && !TraceMode)
|
||||||
|
EE = ExecutionEngine::createJIT(M, Config);
|
||||||
|
|
||||||
|
// If we can't make a JIT, make an interpreter instead.
|
||||||
|
if (EE == 0)
|
||||||
|
EE = ExecutionEngine::createInterpreter(M, Config, DebugMode, TraceMode);
|
||||||
|
|
||||||
|
// Add the module name to the start of the argv vector...
|
||||||
|
InputArgv.insert(InputArgv.begin(), InputFile);
|
||||||
|
|
||||||
|
// Run the main function!
|
||||||
|
int ExitCode = EE->run(MainFunction, InputArgv);
|
||||||
|
|
||||||
|
// Now that we are done executing the program, shut down the execution engine
|
||||||
|
delete EE;
|
||||||
|
return ExitCode;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user