- scriptified the functions in a_possessed.cpp and added the needed exports and constants.

- fixed: Script functions did not receive the function name when being created.
- relaxed the asserts for PARAM_STATE, because the VM knows nothing about ATAG_STATE. Any state variable's content (e.g. Actor.SeeState) will receive ATAG_GENERIC, rather than ATAG_STATE.
- added a 'NeedResult' flag so that certain operations can create shorter code if the result of the expression is not needed. So far only used for postdecrement/increment statements on local variables (which is the most frequent case where this matters.)
- fixed postincrement and decrement for local variables. Due to the result preservation semantics it created faulty code.
This commit is contained in:
Christoph Oelckers 2016-10-26 11:30:30 +02:00
parent 33d00070b5
commit 823c52aeb2
16 changed files with 246 additions and 170 deletions

View file

@ -1519,9 +1519,8 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build)
assert(ValueType == TypeBool);
ExpEmit from = Operand->Emit(build);
assert(!from.Konst);
// ~x & 1
build->Emit(OP_NOT, from.RegNum, from.RegNum, 0);
build->Emit(OP_AND_RK, from.RegNum, from.RegNum, build->GetConstantInt(1));
// boolean not is the same as XOR-ing the lowest bit
build->Emit(OP_XOR_RK, from.RegNum, from.RegNum, build->GetConstantInt(1));
return from;
}
@ -1734,32 +1733,54 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build)
int zero = build->GetConstantInt(0);
int regtype = ValueType->GetRegType();
ExpEmit pointer = Base->Emit(build);
ExpEmit out = pointer;
if (!pointer.Target)
{
out = ExpEmit(build, regtype);
ExpEmit out(build, regtype);
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero);
ExpEmit assign(build, regtype);
if (regtype == REGT_INT)
{
build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, assign.RegNum, out.RegNum, build->GetConstantInt(1));
}
else
{
build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, assign.RegNum, out.RegNum, build->GetConstantFloat(1.));
}
build->Emit(ValueType->GetStoreOp(), pointer.RegNum, out.RegNum, zero);
pointer.Free(build);
assign.Free(build);
return out;
}
ExpEmit assign(build, regtype);
if (regtype == REGT_INT)
else if (NeedResult)
{
build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, assign.RegNum, out.RegNum, build->GetConstantInt(1));
ExpEmit out(build, regtype);
if (regtype == REGT_INT)
{
build->Emit(OP_MOVE, out.RegNum, pointer.RegNum);
build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, pointer.RegNum, pointer.RegNum, build->GetConstantInt(1));
}
else
{
build->Emit(OP_MOVEF, out.RegNum, pointer.RegNum);
build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, pointer.RegNum, pointer.RegNum, build->GetConstantFloat(1.));
}
pointer.Free(build);
return out;
}
else
{
build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, assign.RegNum, out.RegNum, build->GetConstantFloat(1.));
if (regtype == REGT_INT)
{
build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, pointer.RegNum, pointer.RegNum, build->GetConstantInt(1));
}
else
{
build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, pointer.RegNum, pointer.RegNum, build->GetConstantFloat(1.));
}
pointer.Free(build);
return ExpEmit();
}
if (!pointer.Target)
{
build->Emit(ValueType->GetStoreOp(), pointer.RegNum, assign.RegNum, zero);
}
pointer.Free(build);
assign.Free(build);
return out;
}
//==========================================================================
@ -5795,7 +5816,8 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx)
auto x = Condition;
Condition = nullptr;
delete this;
return Condition;
x->NeedResult = false;
return x;
}
}
@ -5805,6 +5827,7 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx)
if (line->ExprType != EFX_JumpStatement || static_cast<FxJumpStatement *>(line)->Token != TK_Break)
{
SAFE_RESOLVE(line, ctx);
line->NeedResult = false;
}
}
@ -5999,6 +6022,8 @@ FxIfStatement::FxIfStatement(FxExpression *cond, FxExpression *true_part,
Condition = cond;
WhenTrue = true_part;
WhenFalse = false_part;
if (WhenTrue != nullptr) WhenTrue->NeedResult = false;
if (WhenFalse != nullptr) WhenFalse->NeedResult = false;
assert(cond != NULL);
}
@ -6338,6 +6363,8 @@ FxForLoop::FxForLoop(FxExpression *init, FxExpression *condition, FxExpression *
: FxLoopStatement(EFX_ForLoop, pos), Init(init), Condition(condition), Iteration(iteration), Code(code)
{
ValueType = TypeVoid;
if (Iteration != nullptr) Iteration->NeedResult = false;
if (Code != nullptr) Code->NeedResult = false;
}
FxForLoop::~FxForLoop()
@ -7139,19 +7166,19 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build)
{
default:
case REGT_INT:
build->Emit(OP_LK, build->GetConstantInt(constval->GetValue().GetInt()), RegNum);
build->Emit(OP_LK, RegNum, build->GetConstantInt(constval->GetValue().GetInt()));
break;
case REGT_FLOAT:
build->Emit(OP_LKF, build->GetConstantFloat(constval->GetValue().GetFloat()), RegNum);
build->Emit(OP_LKF, RegNum, build->GetConstantFloat(constval->GetValue().GetFloat()));
break;
case REGT_POINTER:
build->Emit(OP_LKP, build->GetConstantAddress(constval->GetValue().GetPointer(), ATAG_GENERIC), RegNum);
build->Emit(OP_LKP, RegNum, build->GetConstantAddress(constval->GetValue().GetPointer(), ATAG_GENERIC));
break;
case REGT_STRING:
build->Emit(OP_LKS, build->GetConstantString(constval->GetValue().GetString()), RegNum);
build->Emit(OP_LKS, RegNum, build->GetConstantString(constval->GetValue().GetString()));
}
emitval.Free(build);
}

View file

@ -300,6 +300,7 @@ public:
PType *ValueType = nullptr;
bool isresolved = false;
bool NeedResult = true; // should be set to false if not needed and properly handled by all nodes for their subnodes to eliminate redundant code
EFxType ExprType;
};
@ -1246,7 +1247,7 @@ public:
FxSequence(const FScriptPosition &pos) : FxExpression(EFX_Sequence, pos) {}
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); }
void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); expr->NeedResult = false; }
VMFunction *GetDirectFunction();
};

View file

@ -680,6 +680,7 @@ void InitThingdef()
symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold)));
symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold)));
symt.AddSymbol(new PField(NAME_Damage, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DamageVal)));
symt.AddSymbol(new PField("visdir", TypeSInt32, VARF_Native, myoffsetof(AActor, visdir)));
symt.AddSymbol(new PField(NAME_VisibleStartAngle, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleStartAngle)));
symt.AddSymbol(new PField(NAME_VisibleStartPitch, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleStartPitch)));
symt.AddSymbol(new PField(NAME_VisibleEndAngle, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleEndAngle)));
@ -688,6 +689,7 @@ void InitThingdef()
symt.AddSymbol(new PField("Pos", TypeVector3, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos)));
symt.AddSymbol(new PField("Vel", TypeVector3, VARF_Native, myoffsetof(AActor, Vel)));
symt.AddSymbol(new PField("Scale", TypeVector2, VARF_Native, myoffsetof(AActor, Scale)));
symt.AddSymbol(new PField("SeeState", TypeState, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, SeeState)));
symt.AddSymbol(new PField(NAME_Target, TypeActor, VARF_Native, myoffsetof(AActor, target)));
symt.AddSymbol(new PField(NAME_Master, TypeActor, VARF_Native, myoffsetof(AActor, master)));
symt.AddSymbol(new PField(NAME_Tracer, TypeActor, VARF_Native, myoffsetof(AActor, tracer)));

View file

@ -915,7 +915,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_FLOAT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); double x = param[p].f;
#define PARAM_ANGLE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_FLOAT); DAngle x = param[p].f;
#define PARAM_STRING_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_STRING); FString x = param[p].s();
#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); FState *x = (FState *)param[p].a;
#define PARAM_STATE_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].atag == ATAG_GENERIC || param[p].a == NULL)); FState *x = (FState *)param[p].a;
#define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a;
#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
@ -932,8 +932,8 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_FLOAT_OPT_AT(p,x) double x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = param[p].f; } else
#define PARAM_ANGLE_OPT_AT(p,x) DAngle x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_FLOAT); x = param[p].f; } else
#define PARAM_STRING_OPT_AT(p,x) FString x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_STRING); x = param[p].s(); } else
#define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].a == NULL)); x = (FState *)param[p].a; } else
#define PARAM_STATEINFO_OPT_AT(p,x) FStateParamInfo *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATEINFO || param[p].a == NULL)); x = (FStateParamInfo *)param[p].a; } else
#define PARAM_STATE_OPT_AT(p,x) FState *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATE || param[p].atag == ATAG_GENERIC || param[p].a == NULL)); x = (FState *)param[p].a; } else
#define PARAM_STATEINFO_OPT_AT(p,x) FStateParamInfo *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_STATEINFO || param[p].atag == ATAG_GENERIC || param[p].a == NULL)); x = (FStateParamInfo *)param[p].a; } else
#define PARAM_POINTER_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER); x = (type *)param[p].a; } else
#define PARAM_OBJECT_OPT_AT(p,x,type) type *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type))); } else
#define PARAM_CLASS_OPT_AT(p,x,base) base::MetaClass *x; if ((p) < numparam && param[p].Type != REGT_NIL) { assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base))); } else

View file

@ -665,6 +665,7 @@ VMFunction *FFunctionBuildList::AddFunction(PFunction *functype, FxExpression *c
it.Code = code;
it.PrintableName = name;
it.Function = new VMScriptFunction;
it.Function->Name = functype->SymbolName;
it.Function->ImplicitArgs = functype->GetImplicitArgs();
it.Proto = nullptr;
it.FromDecorate = fromdecorate;