mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-28 19:31:58 +00:00
Implement global variables. Struct and Pointer initializers are not implemented yet though
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@818 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
8d2de8a82c
commit
2e42d3a306
@ -14,6 +14,109 @@
|
||||
#include "llvm/Assembly/Writer.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/GlobalVariable.h"
|
||||
|
||||
// Create a TargetData structure to handle memory addressing and size/alignment
|
||||
// computations
|
||||
//
|
||||
static TargetData TD("lli Interpreter");
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Annotation Wrangling code
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void Interpreter::initializeExecutionEngine() {
|
||||
AnnotationManager::registerAnnotationFactory(MethodInfoAID,
|
||||
&MethodInfo::Create);
|
||||
AnnotationManager::registerAnnotationFactory(GlobalAddressAID,
|
||||
&GlobalAddress::Create);
|
||||
}
|
||||
|
||||
// InitializeMemory - Recursive function to apply a ConstPool value into the
|
||||
// specified memory location...
|
||||
//
|
||||
static void InitializeMemory(ConstPoolVal *Init, char *Addr) {
|
||||
#define INITIALIZE_MEMORY(TYID, CLASS, TY) \
|
||||
case Type::TYID##TyID: { \
|
||||
TY Tmp = cast<CLASS>(Init)->getValue(); \
|
||||
memcpy(Addr, &Tmp, sizeof(TY)); \
|
||||
} return
|
||||
|
||||
switch (Init->getType()->getPrimitiveID()) {
|
||||
INITIALIZE_MEMORY(Bool , ConstPoolBool, bool);
|
||||
INITIALIZE_MEMORY(UByte , ConstPoolUInt, unsigned char);
|
||||
INITIALIZE_MEMORY(SByte , ConstPoolSInt, signed char);
|
||||
INITIALIZE_MEMORY(UShort , ConstPoolUInt, unsigned short);
|
||||
INITIALIZE_MEMORY(Short , ConstPoolSInt, signed short);
|
||||
INITIALIZE_MEMORY(UInt , ConstPoolUInt, unsigned int);
|
||||
INITIALIZE_MEMORY(Int , ConstPoolSInt, signed int);
|
||||
INITIALIZE_MEMORY(ULong , ConstPoolUInt, uint64_t);
|
||||
INITIALIZE_MEMORY(Long , ConstPoolSInt, int64_t);
|
||||
INITIALIZE_MEMORY(Float , ConstPoolFP , float);
|
||||
INITIALIZE_MEMORY(Double , ConstPoolFP , double);
|
||||
#undef INITIALIZE_MEMORY
|
||||
case Type::ArrayTyID: {
|
||||
ConstPoolArray *CPA = cast<ConstPoolArray>(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<ConstPoolVal>(Val[i].get()), Addr+i*ElementSize);
|
||||
return;
|
||||
}
|
||||
// TODO: Struct and Pointer!
|
||||
case Type::StructTyID:
|
||||
case Type::PointerTyID:
|
||||
default:
|
||||
cout << "Bad Type: " << Init->getType()->getDescription() << endl;
|
||||
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<Method>(GVal)) {
|
||||
// The GlobalAddress object for a method is just a pointer to method 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 method 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()->getValueType(); // Type to be allocated
|
||||
unsigned NumElements = 1;
|
||||
|
||||
if (isa<ArrayType>(Ty) && cast<ArrayType>(Ty)->isUnsized()) {
|
||||
assert(GV->hasInitializer() && "Const val must have an initializer!");
|
||||
// Allocating a unsized array type?
|
||||
Ty = cast<const ArrayType>(Ty)->getElementType(); // Get the actual type...
|
||||
|
||||
// Get the number of elements being allocated by the array...
|
||||
NumElements =cast<ConstPoolArray>(GV->getInitializer())->getValues().size();
|
||||
}
|
||||
|
||||
// Allocate enough memory to hold the type...
|
||||
void *Addr = malloc(NumElements * 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
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Value Manipulation code
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static unsigned getOperandSlot(Value *V) {
|
||||
SlotNumber *SN = (SlotNumber*)V->getAnnotation(SlotNumberAID);
|
||||
@ -22,7 +125,7 @@ static unsigned getOperandSlot(Value *V) {
|
||||
}
|
||||
|
||||
#define GET_CONST_VAL(TY, CLASS) \
|
||||
case Type::TY##TyID: Result.TY##Val = ((CLASS*)CPV)->getValue(); break
|
||||
case Type::TY##TyID: Result.TY##Val = cast<CLASS>(CPV)->getValue(); break
|
||||
|
||||
static GenericValue getOperandValue(Value *V, ExecutionContext &SF) {
|
||||
if (ConstPoolVal *CPV = dyn_cast<ConstPoolVal>(V)) {
|
||||
@ -37,10 +140,26 @@ static GenericValue getOperandValue(Value *V, ExecutionContext &SF) {
|
||||
GET_CONST_VAL(Int , ConstPoolSInt);
|
||||
GET_CONST_VAL(Float , ConstPoolFP);
|
||||
GET_CONST_VAL(Double , ConstPoolFP);
|
||||
case Type::PointerTyID:
|
||||
if (isa<ConstPoolPointerNull>(CPV)) {
|
||||
Result.PointerVal = 0;
|
||||
} else if (ConstPoolPointerReference *CPR =
|
||||
dyn_cast<ConstPoolPointerReference>(CPV)) {
|
||||
assert(0 && "Not implemented!");
|
||||
} else {
|
||||
assert(0 && "Unknown constant pointer type!");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cout << "ERROR: Constant unimp for type: " << CPV->getType() << endl;
|
||||
}
|
||||
return Result;
|
||||
} else if (GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
|
||||
GlobalAddress *Address =
|
||||
(GlobalAddress*)GV->getOrCreateAnnotation(GlobalAddressAID);
|
||||
GenericValue Result;
|
||||
Result.PointerVal = (GenericValue*)Address->Ptr;
|
||||
return Result;
|
||||
} else {
|
||||
unsigned TyP = V->getType()->getUniqueID(); // TypePlane for value
|
||||
return SF.Values[TyP][getOperandSlot(V)];
|
||||
@ -48,7 +167,11 @@ static GenericValue getOperandValue(Value *V, ExecutionContext &SF) {
|
||||
}
|
||||
|
||||
static void printOperandInfo(Value *V, ExecutionContext &SF) {
|
||||
if (!isa<ConstPoolVal>(V)) {
|
||||
if (isa<ConstPoolVal>(V)) {
|
||||
cout << "Constant Pool Value\n";
|
||||
} else if (isa<GlobalValue>(V)) {
|
||||
cout << "Global Value\n";
|
||||
} else {
|
||||
unsigned TyP = V->getType()->getUniqueID(); // TypePlane for value
|
||||
unsigned Slot = getOperandSlot(V);
|
||||
cout << "Value=" << (void*)V << " TypeID=" << TyP << " Slot=" << Slot
|
||||
@ -294,7 +417,7 @@ void Interpreter::executeRetInst(ReturnInst *I, ExecutionContext &SF) {
|
||||
if (RetTy) { // Nonvoid return type?
|
||||
cout << "Method " << M->getType() << " \"" << M->getName()
|
||||
<< "\" returned ";
|
||||
printValue(RetTy, Result);
|
||||
print(RetTy, Result);
|
||||
cout << endl;
|
||||
|
||||
if (RetTy->isIntegral())
|
||||
@ -319,7 +442,7 @@ void Interpreter::executeRetInst(ReturnInst *I, ExecutionContext &SF) {
|
||||
// instruction.
|
||||
cout << "Method " << M->getType() << " \"" << M->getName()
|
||||
<< "\" returned ";
|
||||
printValue(RetTy, Result);
|
||||
print(RetTy, Result);
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
@ -341,11 +464,6 @@ void Interpreter::executeBrInst(BranchInst *I, ExecutionContext &SF) {
|
||||
// Memory Instruction Implementations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Create a TargetData structure to handle memory addressing and size/alignment
|
||||
// computations
|
||||
//
|
||||
static TargetData TD("lli Interpreter");
|
||||
|
||||
void Interpreter::executeAllocInst(AllocationInst *I, ExecutionContext &SF) {
|
||||
const Type *Ty = I->getType()->getValueType(); // Type to be allocated
|
||||
unsigned NumElements = 1;
|
||||
@ -367,7 +485,7 @@ void Interpreter::executeAllocInst(AllocationInst *I, ExecutionContext &SF) {
|
||||
SetValue(I, Result, SF);
|
||||
|
||||
if (I->getOpcode() == Instruction::Alloca) {
|
||||
// Keep track to free it later...
|
||||
// TODO: FIXME: alloca should keep track of memory to free it later...
|
||||
}
|
||||
}
|
||||
|
||||
@ -602,10 +720,6 @@ unsigned MethodInfo::getValueSlot(const Value *V) {
|
||||
}
|
||||
|
||||
|
||||
void Interpreter::initializeExecutionEngine() {
|
||||
AnnotationManager::registerAnnotationFactory(MethodInfoAID, CreateMethodInfo);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// callMethod - Execute the specified method...
|
||||
//
|
||||
@ -703,9 +817,6 @@ void Interpreter::stepInstruction() { // Do the 'step' command
|
||||
}
|
||||
|
||||
// --- UI Stuff...
|
||||
|
||||
|
||||
|
||||
void Interpreter::nextInstruction() { // Do the 'next' command
|
||||
if (ECStack.empty()) {
|
||||
cout << "Error: no program running, cannot 'next'!\n";
|
||||
@ -746,7 +857,6 @@ void Interpreter::run() {
|
||||
if (HitBreakpoint) {
|
||||
cout << "Breakpoint hit!\n";
|
||||
}
|
||||
|
||||
// Print the next instruction to execute...
|
||||
printCurrentInstruction();
|
||||
}
|
||||
@ -787,8 +897,6 @@ void Interpreter::printCurrentInstruction() {
|
||||
}
|
||||
|
||||
void Interpreter::printValue(const Type *Ty, GenericValue V) {
|
||||
cout << Ty << " ";
|
||||
|
||||
switch (Ty->getPrimitiveID()) {
|
||||
case Type::BoolTyID: cout << (V.BoolVal?"true":"false"); break;
|
||||
case Type::SByteTyID: cout << V.SByteVal; break;
|
||||
@ -806,15 +914,20 @@ void Interpreter::printValue(const Type *Ty, GenericValue V) {
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::printValue(const string &Name) {
|
||||
void Interpreter::print(const Type *Ty, GenericValue V) {
|
||||
cout << Ty << " ";
|
||||
printValue(Ty, V);
|
||||
}
|
||||
|
||||
void Interpreter::print(const string &Name) {
|
||||
Value *PickedVal = ChooseOneOption(Name, LookupMatchingNames(Name));
|
||||
if (!PickedVal) return;
|
||||
|
||||
if (const Method *M = dyn_cast<const Method>(PickedVal)) {
|
||||
cout << M; // Print the method
|
||||
} else { // Otherwise there should be an annotation for the slot#
|
||||
printValue(PickedVal->getType(),
|
||||
getOperandValue(PickedVal, ECStack[CurFrame]));
|
||||
print(PickedVal->getType(),
|
||||
getOperandValue(PickedVal, ECStack[CurFrame]));
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
@ -825,8 +938,8 @@ void Interpreter::infoValue(const string &Name) {
|
||||
if (!PickedVal) return;
|
||||
|
||||
cout << "Value: ";
|
||||
printValue(PickedVal->getType(),
|
||||
getOperandValue(PickedVal, ECStack[CurFrame]));
|
||||
print(PickedVal->getType(),
|
||||
getOperandValue(PickedVal, ECStack[CurFrame]));
|
||||
cout << endl;
|
||||
printOperandInfo(PickedVal, ECStack[CurFrame]);
|
||||
}
|
||||
|
@ -25,20 +25,19 @@ struct MethodInfo : public Annotation {
|
||||
MethodInfo(Method *M);
|
||||
vector<unsigned> NumPlaneElements;
|
||||
|
||||
|
||||
// Create - Factory function to allow MethodInfo annotations to be
|
||||
// created on demand.
|
||||
//
|
||||
static Annotation *Create(AnnotationID AID, const Annotable *O, void *) {
|
||||
assert(AID == MethodInfoAID);
|
||||
return new MethodInfo(cast<Method>((Value*)O)); // Simply invoke the ctor
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned getValueSlot(const Value *V);
|
||||
};
|
||||
|
||||
// CreateMethodInfo - Factory function to allow MethodInfo annotations to be
|
||||
// created on demand.
|
||||
//
|
||||
inline static Annotation *CreateMethodInfo(AnnotationID AID, const Annotable *O,
|
||||
void *) {
|
||||
assert(AID == MethodInfoAID);
|
||||
return new MethodInfo((Method*)O); // Simply invoke the ctor
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Support for the SlotNumber annotation
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -89,4 +88,32 @@ static AnnotationID BreakpointAID(
|
||||
AnnotationManager::getID("Interpreter::Breakpoint"));
|
||||
// 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 Method's,
|
||||
// this pointer is the Method 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
|
||||
|
@ -91,10 +91,32 @@ void Interpreter::callExternalMethod(Method *M,
|
||||
//
|
||||
extern "C" { // Don't add C++ manglings to llvm mangling :)
|
||||
|
||||
// Implement void printstr([ubyte {x N}] *)
|
||||
GenericValue lle_VP_printstr(MethodType *M, const vector<GenericValue> &ArgVal){
|
||||
assert(ArgVal.size() == 1 && "printstr only takes one argument!");
|
||||
cout << (char*)ArgVal[0].PointerVal;
|
||||
return GenericValue();
|
||||
}
|
||||
|
||||
// Implement 'void print(X)' for every type...
|
||||
GenericValue lle_X_print(MethodType *M, const vector<GenericValue> &ArgVals) {
|
||||
assert(ArgVals.size() == 1 && "generic print only takes one argument!");
|
||||
Interpreter::printValue(M->getParamTypes()[0], ArgVals[0]);
|
||||
|
||||
Interpreter::print(M->getParamTypes()[0], ArgVals[0]);
|
||||
return GenericValue();
|
||||
}
|
||||
|
||||
// Implement 'void printVal(X)' for every type...
|
||||
GenericValue lle_X_printVal(MethodType *M, const vector<GenericValue> &ArgVal) {
|
||||
assert(ArgVal.size() == 1 && "generic print only takes one argument!");
|
||||
|
||||
// Specialize print([ubyte {x N} ] *)
|
||||
if (PointerType *PTy = dyn_cast<PointerType>(M->getParamTypes()[0].get()))
|
||||
if (const ArrayType *ATy = dyn_cast<ArrayType>(PTy->getValueType())) {
|
||||
return lle_VP_printstr(M, ArgVal);
|
||||
}
|
||||
|
||||
Interpreter::printValue(M->getParamTypes()[0], ArgVal[0]);
|
||||
return GenericValue();
|
||||
}
|
||||
|
||||
@ -104,4 +126,10 @@ GenericValue lle_Vb_putchar(MethodType *M, const vector<GenericValue> &Args) {
|
||||
return GenericValue();
|
||||
}
|
||||
|
||||
// void "putchar"(ubyte)
|
||||
GenericValue lle_VB_putchar(MethodType *M, const vector<GenericValue> &Args) {
|
||||
cout << Args[0].UByteVal;
|
||||
return GenericValue();
|
||||
}
|
||||
|
||||
} // End extern "C"
|
||||
|
@ -74,10 +74,13 @@ public:
|
||||
void handleUserInput();
|
||||
|
||||
// User Interation Methods...
|
||||
void loadModule(const string &Filename);
|
||||
bool flushModule();
|
||||
bool callMethod(const string &Name); // return true on failure
|
||||
void setBreakpoint(const string &Name);
|
||||
void infoValue(const string &Name);
|
||||
void printValue(const string &Name);
|
||||
void print(const string &Name);
|
||||
static void print(const Type *Ty, GenericValue V);
|
||||
static void printValue(const Type *Ty, GenericValue V);
|
||||
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Interpreter.h"
|
||||
#include "llvm/Bytecode/Reader.h"
|
||||
#include "llvm/Assembly/Writer.h"
|
||||
#include <algorithm>
|
||||
|
||||
@ -81,9 +82,14 @@ void Interpreter::handleUserInput() {
|
||||
|
||||
switch (E->CID) {
|
||||
case Quit: UserQuit = true; break;
|
||||
case Load:
|
||||
cin >> Command;
|
||||
loadModule(Command);
|
||||
break;
|
||||
case Flush: flushModule(); break;
|
||||
case Print:
|
||||
cin >> Command;
|
||||
printValue(Command);
|
||||
print(Command);
|
||||
break;
|
||||
case Info:
|
||||
cin >> Command;
|
||||
@ -118,6 +124,43 @@ void Interpreter::handleUserInput() {
|
||||
} while (!UserQuit);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// loadModule - Load a new module to execute...
|
||||
//
|
||||
void Interpreter::loadModule(const string &Filename) {
|
||||
if (CurMod && !flushModule()) return; // Kill current execution
|
||||
|
||||
CurMod = ParseBytecodeFile(Filename);
|
||||
if (CurMod == 0) {
|
||||
cout << "Error parsing '" << Filename << "': No module loaded.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: link in support library...
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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;
|
||||
}
|
||||
|
||||
delete CurMod;
|
||||
CurMod = 0;
|
||||
ExitCode = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// setBreakpoint - Enable a breakpoint at the specified location
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "Interpreter.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Bytecode/Reader.h"
|
||||
|
||||
cl::String InputFilename("" , "Input filename", cl::NoFlags, "-");
|
||||
cl::String MainFunction ("f" , "Function to execute", cl::NoFlags, "main");
|
||||
@ -21,10 +20,8 @@ cl::Flag ProfileMode ("profile", "Enable Profiling [unimp]");
|
||||
// Interpreter ctor - Initialize stuff
|
||||
//
|
||||
Interpreter::Interpreter() : ExitCode(0), Profile(ProfileMode), CurFrame(-1) {
|
||||
CurMod = ParseBytecodeFile(InputFilename);
|
||||
if (CurMod == 0) {
|
||||
cout << "Error parsing '" << InputFilename << "': No module loaded.\n";
|
||||
}
|
||||
CurMod = 0;
|
||||
loadModule(InputFilename);
|
||||
|
||||
// Initialize the "backend"
|
||||
initializeExecutionEngine();
|
||||
|
Loading…
Reference in New Issue
Block a user