- Added PARAMI for the common case of passing an integer constant to a function.

- Made FxParameter::Emit free its operand's register.

SVN r1918 (scripting)
This commit is contained in:
Randy Heit 2009-10-15 21:59:37 +00:00
parent caa5f6dbdc
commit 126c738116
6 changed files with 61 additions and 75 deletions

View file

@ -334,6 +334,7 @@ FxParameter::FxParameter(FxExpression *operand)
: FxExpression(operand->ScriptPosition) : FxExpression(operand->ScriptPosition)
{ {
Operand = operand; Operand = operand;
ValueType = operand->ValueType;
} }
//========================================================================== //==========================================================================
@ -357,9 +358,23 @@ FxExpression *FxParameter::Resolve(FCompileContext& ctx)
{ {
CHECKRESOLVED(); CHECKRESOLVED();
SAFE_RESOLVE(Operand, ctx); SAFE_RESOLVE(Operand, ctx);
ValueType = Operand->ValueType;
return this; return this;
} }
static void EmitConstantInt(VMFunctionBuilder *build, int val)
{
// If it fits in 24 bits, use PARAMI instead of PARAM.
if ((val << 8) >> 8)
{
build->Emit(OP_PARAMI, val);
}
else
{
build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, build->GetConstantInt(val));
}
}
ExpEmit FxParameter::Emit(VMFunctionBuilder *build) ExpEmit FxParameter::Emit(VMFunctionBuilder *build)
{ {
if (Operand->isConstant()) if (Operand->isConstant())
@ -367,7 +382,7 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build)
ExpVal val = Operand->EvalExpression(NULL); ExpVal val = Operand->EvalExpression(NULL);
if (val.Type == VAL_Int || val.Type == VAL_Sound || val.Type == VAL_Name || val.Type == VAL_Color) if (val.Type == VAL_Int || val.Type == VAL_Sound || val.Type == VAL_Name || val.Type == VAL_Color)
{ {
build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, build->GetConstantInt(val.Int)); EmitConstantInt(build, val.Int);
} }
else if (val.Type == VAL_Float) else if (val.Type == VAL_Float)
{ {
@ -398,6 +413,7 @@ ExpEmit FxParameter::Emit(VMFunctionBuilder *build)
else else
{ {
build->Emit(OP_PARAM, 0, where.RegType, where.RegNum); build->Emit(OP_PARAM, 0, where.RegType, where.RegNum);
build->FreeReg(where.RegType, where.RegNum);
} }
} }
return ExpEmit(); return ExpEmit();
@ -2366,8 +2382,8 @@ FxRandom::FxRandom(FRandom * r, FxExpression *mi, FxExpression *ma, const FScrip
{ {
if (mi != NULL && ma != NULL) if (mi != NULL && ma != NULL)
{ {
min = new FxIntCast(mi); min = new FxParameter(new FxIntCast(mi));
max = new FxIntCast(ma); max = new FxParameter(new FxIntCast(ma));
} }
else min = max = NULL; else min = max = NULL;
rng = r; rng = r;
@ -2397,17 +2413,11 @@ FxExpression *FxRandom::Resolve(FCompileContext &ctx)
CHECKRESOLVED(); CHECKRESOLVED();
if (min && max) if (min && max)
{ {
if (min->ValueType != VAL_Int)
{
min = new FxIntCast(min);
}
if (max->ValueType != VAL_Int)
{
max = new FxIntCast(max);
}
RESOLVE(min, ctx); RESOLVE(min, ctx);
RESOLVE(max, ctx); RESOLVE(max, ctx);
ABORT(min && max); ABORT(min && max);
assert(min->ValueType == VAL_Int);
assert(max->ValueType == VAL_Int);
} }
return this; return this;
}; };
@ -2489,28 +2499,8 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build)
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG));
if (min != NULL && max != NULL) if (min != NULL && max != NULL)
{ {
ExpEmit op = min->Emit(build); min->Emit(build);
assert(op.RegType == REGT_INT); max->Emit(build);
if (op.Konst)
{
build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, op.RegNum);
}
else
{
build->FreeReg(REGT_INT, op.RegNum);
build->Emit(OP_PARAM, 0, REGT_INT, op.RegNum);
}
op = max->Emit(build);
assert(op.RegType == REGT_INT);
if (op.Konst)
{
build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, op.RegNum);
}
else
{
build->FreeReg(REGT_INT, op.RegNum);
build->Emit(OP_PARAM, 0, REGT_INT, op.RegNum);
}
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1);
} }
else else
@ -2532,8 +2522,8 @@ FxFRandom::FxFRandom(FRandom *r, FxExpression *mi, FxExpression *ma, const FScri
{ {
if (mi != NULL && ma != NULL) if (mi != NULL && ma != NULL)
{ {
min = mi; min = new FxParameter(new FxFloatCast(mi));
max = ma; max = new FxParameter(new FxFloatCast(ma));
} }
} }
@ -2614,28 +2604,8 @@ ExpEmit FxFRandom::Emit(VMFunctionBuilder *build)
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG));
if (min != NULL && max != NULL) if (min != NULL && max != NULL)
{ {
ExpEmit op = min->Emit(build); min->Emit(build);
assert(op.RegType == REGT_FLOAT); max->Emit(build);
if (op.Konst)
{
build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, op.RegNum);
}
else
{
build->FreeReg(REGT_FLOAT, op.RegNum);
build->Emit(OP_PARAM, 0, REGT_FLOAT, op.RegNum);
}
op = max->Emit(build);
assert(op.RegType == REGT_FLOAT);
if (op.Konst)
{
build->Emit(OP_PARAM, 0, REGT_FLOAT | REGT_KONST, op.RegNum);
}
else
{
build->FreeReg(REGT_FLOAT, op.RegNum);
build->Emit(OP_PARAM, 0, REGT_FLOAT, op.RegNum);
}
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 3, 1);
} }
else else
@ -2659,6 +2629,7 @@ FxRandom2::FxRandom2(FRandom *r, FxExpression *m, const FScriptPosition &pos)
rng = r; rng = r;
if (m) mask = new FxIntCast(m); if (m) mask = new FxIntCast(m);
else mask = new FxConstant(-1, pos); else mask = new FxConstant(-1, pos);
mask = new FxParameter(mask);
ValueType = VAL_Int; ValueType = VAL_Int;
} }
@ -2721,17 +2692,7 @@ ExpEmit FxRandom2::Emit(VMFunctionBuilder *build)
callfunc = ((PSymbolVMFunction *)sym)->Function; callfunc = ((PSymbolVMFunction *)sym)->Function;
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG)); build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(rng, ATAG_RNG));
ExpEmit op = mask->Emit(build); mask->Emit(build);
assert(op.RegType == REGT_INT);
if (op.Konst)
{
build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, op.RegNum);
}
else
{
build->FreeReg(REGT_INT, op.RegNum);
build->Emit(OP_PARAM, 0, REGT_INT, op.RegNum);
}
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1); build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1);
ExpEmit out(build, REGT_INT); ExpEmit out(build, REGT_INT);
build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum); build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum);
@ -3513,17 +3474,22 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
assert(Self == NULL); assert(Self == NULL);
unsigned i = 0; unsigned i = 0;
build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, build->GetConstantInt(Special)); // pass special number build->Emit(OP_PARAMI, Special); // pass special number
build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self
if (ArgList != NULL) if (ArgList != NULL)
{ {
for (; i < ArgList->Size(); ++i) for (; i < ArgList->Size(); ++i)
{ {
ExpEmit arg((*ArgList)[i]->Emit(build)); FxExpression *argex = (*ArgList)[i];
assert(arg.RegType == REGT_INT); assert(argex->ValueType == VAL_Int);
build->Emit(OP_PARAM, 0, arg.RegType | (arg.Konst ? REGT_KONST : 0), arg.RegNum); if (argex->isConstant())
if (!arg.Konst)
{ {
EmitConstantInt(build, argex->EvalExpression(NULL).GetInt());
}
else
{
ExpEmit arg(argex->Emit(build));
build->Emit(OP_PARAM, 0, arg.RegType, arg.RegNum);
build->FreeReg(arg.RegType, arg.RegNum); build->FreeReg(arg.RegType, arg.RegNum);
} }
} }
@ -3991,7 +3957,7 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build)
build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self
for (unsigned i = 0; i < names.Size(); ++i) for (unsigned i = 0; i < names.Size(); ++i)
{ {
build->Emit(OP_PARAM, 0, REGT_INT | REGT_KONST, build->GetConstantInt(names[i])); EmitConstantInt(build, names[i]);
} }
// Find the DecoFindMultiNameState function. If not found, create it and install it // Find the DecoFindMultiNameState function. If not found, create it and install it

View file

@ -465,6 +465,10 @@ size_t VMFunctionBuilder::Emit(int opcode, int opabc)
#else #else
*(VM_UWORD *)&Code[loc] = opcode | (opabc << 8); *(VM_UWORD *)&Code[loc] = opcode | (opabc << 8);
#endif #endif
if (opcode == OP_PARAMI)
{
ParamChange(1);
}
return loc / 4; return loc / 4;
} }

View file

@ -95,8 +95,10 @@ const VMOpInfo OpInfo[NUM_OPS] =
}; };
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
#define ABCs(x) ((*(VM_SWORD *)(x) << 8) >> 8)
#define JMPOFS(x) ((*(VM_SWORD *)(x) << 8) >> 6) #define JMPOFS(x) ((*(VM_SWORD *)(x) << 8) >> 6)
#else #else
#define ABCs(x) (*(VM_SWORD *)(x) >> 8)
#define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3) #define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3)
#endif #endif
@ -214,6 +216,10 @@ void VMDisasm(FILE *out, const VM_UBYTE *code, int codesize, const VMScriptFunct
col = printf_wrapper(out, "%08x", i + 4 + JMPOFS(&code[i])); col = printf_wrapper(out, "%08x", i + 4 + JMPOFS(&code[i]));
break; break;
case OP_PARAMI:
col = printf_wrapper(out, "%d", i + 4 + ABCs(&code[i]));
break;
case OP_RET: case OP_RET:
if (code[i+2] != REGT_NIL) if (code[i+2] != REGT_NIL)
{ {

View file

@ -25,8 +25,10 @@
#define BCs (*(VM_SHALF *)(pc - 2)) #define BCs (*(VM_SHALF *)(pc - 2))
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
#define ABCs ((*(VM_SWORD *)(pc - 4) << 8) >> 8)
#define JMPOFS(x) ((*(VM_SWORD *)(x) << 8) >> 6) #define JMPOFS(x) ((*(VM_SWORD *)(x) << 8) >> 6)
#else #else
#define ABCs (*(VM_SWORD *)(pc - 4) >> 8)
#define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3) #define JMPOFS(x) ((*(VM_SWORD *)(x) >> 6) & ~3)
#endif #endif

View file

@ -395,6 +395,13 @@ begin:
assert(*pc == OP_JMP); assert(*pc == OP_JMP);
pc += (1 + *((VM_SHALF *)pc + 1)) << 2; pc += (1 + *((VM_SHALF *)pc + 1)) << 2;
NEXTOP; NEXTOP;
OP(PARAMI):
assert(f->NumParam < sfunc->MaxParam);
{
VMValue *param = &reg.param[f->NumParam++];
::new(param) VMValue(ABCs);
}
NEXTOP;
OP(PARAM): OP(PARAM):
assert(f->NumParam < sfunc->MaxParam); assert(f->NumParam < sfunc->MaxParam);
{ {

View file

@ -74,6 +74,7 @@ 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(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(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 (B=regtype, C=regnum) xx(PARAM, param, __BCP), // push parameter encoded in BC for function call (B=regtype, C=regnum)
xx(PARAMI, parami, I24), // push immediate, signed integer for function call
xx(CALL, call, RPI8I8), // Call function pkA with parameter count B and expected result count C xx(CALL, call, RPI8I8), // Call function pkA with parameter count B and expected result count C
xx(CALL_K, call, KPI8I8), xx(CALL_K, call, KPI8I8),
xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL) xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL)
@ -106,7 +107,7 @@ xx(SRA_RI, sra, RIRII8),
xx(SRA_KR, sra, RIKIRI), xx(SRA_KR, sra, RIKIRI),
xx(ADD_RR, add, RIRIRI), // dA = dB + dkC xx(ADD_RR, add, RIRIRI), // dA = dB + dkC
xx(ADD_RK, add, RIRIKI), xx(ADD_RK, add, RIRIKI),
xx(ADDI, add, RIRIIs), // dA = dB + C -- C is a signed 8-bit constant xx(ADDI, addi, RIRIIs), // dA = dB + C -- C is a signed 8-bit constant
xx(SUB_RR, sub, RIRIRI), // dA = dkB - dkC xx(SUB_RR, sub, RIRIRI), // dA = dkB - dkC
xx(SUB_RK, sub, RIRIKI), xx(SUB_RK, sub, RIRIKI),
xx(SUB_KR, sub, RIKIRI), xx(SUB_KR, sub, RIKIRI),