- Added some code for generating VM code from FxExpressions. This is completely untested, since

it isn't even used anywhere yet. In retrospect, I probably should have targeted an intermediate
  representation and done codegen with that instead, since that would be something I can reuse.

SVN r1908 (scripting)
This commit is contained in:
Randy Heit 2009-10-11 00:02:14 +00:00
parent e9db2c83a5
commit 3001708d16
8 changed files with 1430 additions and 30 deletions

View file

@ -42,12 +42,14 @@
#include "m_random.h"
#define CHECKRESOLVED() if (isresolved) return this; isresolved=true;
#define SAFE_DELETE(p) if (p!=NULL) { delete p; p=NULL; }
#define RESOLVE(p,c) if (p!=NULL) p = p->Resolve(c)
#define ABORT(p) if (!(p)) { delete this; return NULL; }
#define SAFE_RESOLVE(p,c) RESOLVE(p,c); ABORT(p)
class VMFunctionBuilder;
extern PSymbolTable GlobalSymbols;
//==========================================================================
@ -142,6 +144,15 @@ struct ExpVal
};
struct ExpEmit
{
ExpEmit() : RegNum(0), RegType(REGT_NIL) {}
ExpEmit(int reg, int type) : RegNum(reg), RegType(type) {}
ExpEmit(int reg, int type, bool konst) : RegNum(reg), RegType(type), Konst(konst) {}
ExpEmit(VMFunctionBuilder *build, int type);
BYTE RegNum, RegType, Konst;
};
//==========================================================================
//
@ -166,12 +177,25 @@ public:
virtual bool isConstant() const;
virtual void RequestAddress();
virtual ExpEmit Emit(VMFunctionBuilder *build);
FScriptPosition ScriptPosition;
FExpressionType ValueType;
bool isresolved;
};
class FxParameter : public FxExpression
{
FxExpression *Operand;
public:
FxParameter(FxExpression*);
~FxParameter();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxIdentifier
@ -310,6 +334,21 @@ public:
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
class FxFloatCast : public FxExpression
{
FxExpression *basex;
public:
FxFloatCast(FxExpression *x);
~FxFloatCast();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
@ -327,6 +366,7 @@ public:
FxPlusSign(FxExpression*);
~FxPlusSign();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -344,6 +384,7 @@ public:
~FxMinusSign();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -361,6 +402,7 @@ public:
~FxUnaryNotBitwise();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -378,6 +420,7 @@ public:
~FxUnaryNotBoolean();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -396,6 +439,7 @@ public:
FxBinary(int, FxExpression*, FxExpression*);
~FxBinary();
bool ResolveLR(FCompileContext& ctx, bool castnumeric);
void Promote();
};
//==========================================================================
@ -411,6 +455,7 @@ public:
FxAddSub(int, FxExpression*, FxExpression*);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -426,6 +471,7 @@ public:
FxMulDiv(int, FxExpression*, FxExpression*);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -441,6 +487,7 @@ public:
FxCompareRel(int, FxExpression*, FxExpression*);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -456,6 +503,7 @@ public:
FxCompareEq(int, FxExpression*, FxExpression*);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -471,6 +519,7 @@ public:
FxBinaryInt(int, FxExpression*, FxExpression*);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -491,6 +540,7 @@ public:
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -511,6 +561,7 @@ public:
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -530,6 +581,7 @@ public:
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -551,6 +603,7 @@ public:
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -564,6 +617,7 @@ class FxFRandom : public FxRandom
public:
FxFRandom(FRandom *, FxExpression *mi, FxExpression *ma, const FScriptPosition &pos);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -584,6 +638,7 @@ public:
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
@ -623,6 +678,7 @@ public:
FxExpression *Resolve(FCompileContext&);
void RequestAddress();
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -637,6 +693,7 @@ public:
FxSelf(const FScriptPosition&);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -657,6 +714,7 @@ public:
FxExpression *Resolve(FCompileContext&);
//void RequestAddress();
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
@ -700,6 +758,7 @@ public:
~FxActionSpecialCall();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -719,6 +778,7 @@ public:
~FxGlobalFunctionCall();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
@ -739,6 +799,7 @@ public:
~FxClassTypeCast();
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
@ -775,6 +836,7 @@ public:
FxMultiNameState(const char *statestring, const FScriptPosition &pos);
FxExpression *Resolve(FCompileContext&);
ExpVal EvalExpression (AActor *self);
ExpEmit Emit(VMFunctionBuilder *build);
};

File diff suppressed because it is too large Load diff

View file

@ -107,6 +107,7 @@ enum
ATAG_AREGISTER, // pointer to an address register
ATAG_STATE, // pointer to FState
ATAG_RNG, // pointer to FRandom
};
class VMFunction : public DObject

View file

@ -61,10 +61,10 @@ VMScriptFunction *VMFunctionBuilder::MakeFunction()
}
// Assign required register space.
func->NumRegD = IntRegisters.MostUsed;
func->NumRegF = FloatRegisters.MostUsed;
func->NumRegA = AddressRegisters.MostUsed;
func->NumRegS = StringRegisters.MostUsed;
func->NumRegD = Registers[REGT_INT].MostUsed;
func->NumRegF = Registers[REGT_FLOAT].MostUsed;
func->NumRegA = Registers[REGT_POINTER].MostUsed;
func->NumRegS = Registers[REGT_STRING].MostUsed;
func->MaxParam = MaxParam;
// Technically, there's no reason why we can't end the function with
@ -274,7 +274,7 @@ VMFunctionBuilder::RegAvailability::RegAvailability()
//==========================================================================
//
// VMFunctionBuilder :: RegAvailibity :: GetReg
// VMFunctionBuilder :: RegAvailibity :: Get
//
// Gets one or more unused registers. If getting multiple registers, they
// will all be consecutive. Returns -1 if there were not enough consecutive
@ -286,7 +286,7 @@ VMFunctionBuilder::RegAvailability::RegAvailability()
//
//==========================================================================
int VMFunctionBuilder::RegAvailability::GetReg(int count)
int VMFunctionBuilder::RegAvailability::Get(int count)
{
VM_UWORD mask;
int i, firstbit;
@ -368,13 +368,13 @@ int VMFunctionBuilder::RegAvailability::GetReg(int count)
//==========================================================================
//
// VMFunctionBuilder :: RegAvailibity :: ReturnReg
// VMFunctionBuilder :: RegAvailibity :: Return
//
// Marks a range of registers as free again.
//
//==========================================================================
void VMFunctionBuilder::RegAvailability::ReturnReg(int reg, int count)
void VMFunctionBuilder::RegAvailability::Return(int reg, int count)
{
assert(count >= 1 && count <= 32);
assert(reg >= 0 && reg + count <= 256);
@ -406,8 +406,108 @@ void VMFunctionBuilder::RegAvailability::ReturnReg(int reg, int count)
}
}
void VMFunctionBuilder::RegAvailability::Dump()
//==========================================================================
//
// VMFunctionBuilder :: Emit
//
// Just dumbly output an instruction. Returns instruction position, not
// byte position. (Because all instructions are exactly four bytes long.)
//
//==========================================================================
size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc)
{
Printf("%032B %032B %032B %032B\n%032B %032B %032B %032B\n",
Used[0], Used[1], Used[2], Used[3], Used[4], Used[5], Used[6], Used[7]);
assert(opcode >= 0 && opcode < NUM_OPS);
assert(opa >= 0 && opa <= 255);
assert(opb >= 0 && opb <= 255);
assert(opc >= 0 && opc <= 255);
size_t loc = Code.Reserve(4);
VM_UBYTE *code = &Code[loc];
code[0] = opcode;
code[1] = opa;
code[2] = opb;
code[3] = opc;
return loc / 4;
}
size_t VMFunctionBuilder::Emit(int opcode, int opa, VM_SHALF opbc)
{
assert(opcode >= 0 && opcode < NUM_OPS);
assert(opa >= 0 && opa <= 255);
assert(opbc >= -32768 && opbc <= 32767);
size_t loc = Code.Reserve(4);
VM_UBYTE *code = &Code[loc];
code[0] = opcode;
code[1] = opa;
*(VM_SHALF *)&code[2] = opbc;
return loc / 4;
}
size_t VMFunctionBuilder::Emit(int opcode, int opabc)
{
assert(opcode >= 0 && opcode < NUM_OPS);
assert(opabc >= -(1 << 23) && opabc <= (1 << 24) - 1);
size_t loc = Code.Reserve(4);
#ifdef __BIG_ENDIAN__
*(VM_UWORD *)&Code[loc] = (opabc & 0xFFFFFF) | (opcode << 24);
#else
*(VM_UWORD *)&Code[loc] = opcode | (opabc << 8);
#endif
return loc / 4;
}
//==========================================================================
//
// VMFunctionBuilder :: EmitLoadInt
//
// Loads an integer constant into a register, using either an immediate
// value or a constant register, as appropriate.
//
//==========================================================================
size_t VMFunctionBuilder::EmitLoadInt(int regnum, int value)
{
assert(regnum >= 0 && regnum < Registers[REGT_INT].MostUsed);
if (value >= -32768 && value <= 32767)
{
return Emit(OP_LI, regnum, value);
}
else
{
return Emit(OP_LK, regnum, GetConstantInt(value));
}
}
//==========================================================================
//
// VMFunctionBuilder :: Backpatch
//
// Store a JMP instruction at <loc> that points at <target>.
//
//==========================================================================
void VMFunctionBuilder::Backpatch(size_t loc, size_t target)
{
assert(loc < Code.Size() / 4);
int offset = int(target - loc - 1);
assert(offset >= -(1 << 24) && offset <= (1 << 24) - 1);
#ifdef __BIG_ENDIAN__
*(VM_UWORD *)&Code[loc * 4] = (offset & 0xFFFFFF) | (OP_JMP << 24);
#else
*(VM_UWORD *)&Code[loc * 4] = OP_JMP | (offset << 8);
#endif
}
//==========================================================================
//
// VMFunctionBuilder :: BackpatchToHere
//
// Store a JMP instruction at <loc> that points to the current code gen
// location.
//
//==========================================================================
void VMFunctionBuilder::BackpatchToHere(size_t loc)
{
Backpatch(loc, Code.Size() / 4);
}

View file

@ -11,9 +11,8 @@ public:
{
public:
RegAvailability();
int GetReg(int count); // Returns the first register in the range
void ReturnReg(int reg, int count);
void Dump();
int Get(int count); // Returns the first register in the range
void Return(int reg, int count);
private:
VM_UWORD Used[256/32]; // Bitmap of used registers (bit set means reg is used)
@ -35,6 +34,12 @@ public:
// Returns the address of the newly-emitted instruction.
size_t Emit(int opcode, int opa, int opb, int opc);
size_t Emit(int opcode, int opa, VM_SHALF opbc);
size_t Emit(int opcode, int opabc);
size_t EmitLoadInt(int regnum, int value);
void Backpatch(size_t addr, size_t target);
void BackpatchToHere(size_t addr);
// Write out complete constant tables.
void FillIntConstants(int *konst);
@ -46,10 +51,10 @@ public:
void ParamChange(int delta);
// Track available registers.
RegAvailability IntRegisters;
RegAvailability FloatRegisters;
RegAvailability AddressRegisters;
RegAvailability StringRegisters;
RegAvailability Registers[4];
// Free a register.
void FreeReg(int regtype, int regnum);
private:
struct AddrKonst

View file

@ -30,8 +30,8 @@
#define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3)
#endif
#define KC (konst[C])
#define RC (reg.i[C])
#define KC (konstd[C])
#define RC (reg.d[C])
#define PA (reg.a[A])
#define PB (reg.a[B])
@ -61,11 +61,12 @@ enum
X_READ_NIL,
X_WRITE_NIL,
X_TOO_MANY_TRIES,
X_ARRAY_OUT_OF_BOUNDS
};
#define GETADDR(a,o,x) \
if (a == 0) { THROW(x); } \
ptr = (VM_SBYTE *)a + x \
if (a == NULL) { THROW(x); } \
ptr = (VM_SBYTE *)a + o
static const VM_UWORD ZapTable[16] =
{

View file

@ -586,6 +586,13 @@ begin:
assert(0);
NEXTOP;
OP(BOUND):
if (reg.d[a] >= BC)
{
THROW(X_ARRAY_OUT_OF_BOUNDS);
}
NEXTOP;
OP(CONCAT):
ASSERTS(a); ASSERTS(B); ASSERTS(C);
{

View file

@ -73,7 +73,7 @@ xx(DYNCAST_K, dyncast,RPRPKP),
xx(TEST, test, RII16), // if (dA != BC) then pc++
xx(JMP, jmp, I24), // pc += ABC -- The ABC fields contain a signed 24-bit offset.
xx(IJMP, ijmp, RII16), // pc += dA + BC -- BC is a signed offset. The target instruction must be a JMP.
xx(PARAM, param, __BCP), // push parameter encoded in BC for function call or result for return
xx(PARAM, param, __BCP), // push parameter encoded in BC for function call (B=regtype, C=regnum)
xx(CALL, call, RPI8I8), // Call function pkA with parameter count B and expected result count C
xx(CALL_K, call, KPI8I8),
xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL)
@ -87,6 +87,7 @@ xx(CATCH, catch, CATCH), // A == 0: continue search on next try
// A == 2: (pB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH
// A == 3: (pkB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH
// for A > 0, exception is stored in pC
xx(BOUND, bound, RII16), // if rA >= BC, throw exception
// String instructions.
xx(CONCAT, concat, RSRSRS), // sA = sB.. ... ..sC
@ -129,7 +130,7 @@ xx(MAX_RR, max, RIRIRI), // dA = max(dB,dkC)
xx(MAX_RK, max, RIRIKI),
xx(ABS, abs, RIRI), // dA = abs(dB)
xx(NEG, neg, RIRI), // dA = -dB
xx(NOT, not, RIRI), // dA = !dB
xx(NOT, not, RIRI), // dA = ~dB
xx(SEXT, sext, RIRII8), // dA = dB, sign extended by shifting left then right by C
xx(ZAP_R, zap, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are one
xx(ZAP_I, zap, RIRII8),