From 9400f97189543987bec49fccdf2ceed1069bab6c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 28 Oct 2016 15:15:30 +0200 Subject: [PATCH] - implemented local vector variables. Currently only the definition plus initial assignment works. - removed all vector4 handling that had already been added, now that this type can no longer be defined. --- src/scripting/codegeneration/codegen.cpp | 208 ++++++++++++++++++++++- src/scripting/codegeneration/codegen.h | 29 +++- src/scripting/vm/vm.h | 2 +- src/scripting/zscript/ast.cpp | 14 +- src/scripting/zscript/zcc-parse.lemon | 49 +++--- src/scripting/zscript/zcc_compile.cpp | 14 +- src/scripting/zscript/zcc_parser.cpp | 5 +- src/scripting/zscript/zcc_parser.h | 1 - 8 files changed, 278 insertions(+), 44 deletions(-) diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 3eaaa7170..773fc4b1a 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -178,8 +178,8 @@ FxLocalVariableDeclaration *FCompileContext::FindLocalVariable(FName name) // //========================================================================== -ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) -: RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false), Final(false), Target(false) +ExpEmit::ExpEmit(VMFunctionBuilder *build, int type, int count) +: RegNum(build->Registers[type].Get(count)), RegType(type), RegCount(count), Konst(false), Fixed(false), Final(false), Target(false) { } @@ -187,7 +187,7 @@ void ExpEmit::Free(VMFunctionBuilder *build) { if (!Fixed && !Konst && RegType <= REGT_TYPE) { - build->Registers[RegType].Return(RegNum, 1); + build->Registers[RegType].Return(RegNum, RegCount); } } @@ -195,6 +195,7 @@ void ExpEmit::Reuse(VMFunctionBuilder *build) { if (!Fixed && !Konst) { + assert(RegCount == 1); bool success = build->Registers[RegType].Reuse(RegNum); assert(success && "Attempt to reuse a register that is already in use"); } @@ -434,6 +435,200 @@ ExpEmit FxConstant::Emit(VMFunctionBuilder *build) // //========================================================================== +FxVectorInitializer::FxVectorInitializer(FxExpression *x, FxExpression *y, FxExpression *z, const FScriptPosition &sc) + :FxExpression(EFX_VectorInitializer, sc) +{ + xyz[0] = x; + xyz[1] = y; + xyz[2] = z; + isConst = false; + ValueType = TypeVoid; // we do not know yet +} + +FxVectorInitializer::~FxVectorInitializer() +{ + for (auto &a : xyz) + SAFE_DELETE(a); +} + +FxExpression *FxVectorInitializer::Resolve(FCompileContext&ctx) +{ + bool fails = false; + + for (auto &a : xyz) + { + if (a != nullptr) + { + a = a->Resolve(ctx); + if (a == nullptr) fails = true; + else + { + if (a->ValueType != TypeVector2) // a vec3 may be initialized with (vec2, z) + { + a = new FxFloatCast(a); + a = a->Resolve(ctx); + fails |= (a == nullptr); + } + } + } + } + if (fails) + { + delete this; + return nullptr; + } + // at this point there are three legal cases: + // * two floats = vector2 + // * three floats = vector3 + // * vector2 + float = vector3 + if (xyz[0]->ValueType == TypeVector2) + { + if (xyz[1]->ValueType != TypeFloat64 || xyz[2] != nullptr) + { + ScriptPosition.Message(MSG_ERROR, "Not a valid vector"); + delete this; + return nullptr; + } + ValueType = TypeVector3; + if (xyz[0]->ExprType == EFX_VectorInitializer) + { + // If two vector initializers are nested, unnest them now. + auto vi = static_cast(xyz[0]); + xyz[2] = xyz[1]; + xyz[1] = vi->xyz[1]; + xyz[0] = vi->xyz[0]; + delete vi; + } + } + else if (xyz[0]->ValueType == TypeFloat64 && xyz[1]->ValueType == TypeFloat64) + { + ValueType = xyz[2] == nullptr ? TypeVector2 : TypeVector3; + } + else + { + ScriptPosition.Message(MSG_ERROR, "Not a valid vector"); + delete this; + return nullptr; + } + + // check if all elements are constant. If so this can be emitted as a constant vector. + isConst = true; + for (auto &a : xyz) + { + if (a != nullptr && !a->isConstant()) isConst = false; + } + return this; +} + +static ExpEmit EmitKonst(VMFunctionBuilder *build, ExpEmit &emit) +{ + if (emit.Konst) + { + ExpEmit out(build, REGT_FLOAT); + build->Emit(OP_LKF, out.RegNum, emit.RegNum); + return out; + } + return emit; +} + +ExpEmit FxVectorInitializer::Emit(VMFunctionBuilder *build) +{ + // no const handling here. Ultimstely it's too rarely used (i.e. the only fully constant vector ever allocated in ZDoom is the 0-vector in a very few places) + // and the negatives (excessive allocation of float constants) outweigh the positives (saved a few instructions) + assert(xyz[0] != nullptr); + assert(xyz[1] != nullptr); + if (ValueType == TypeVector2) + { + ExpEmit xval = EmitKonst(build, xyz[0]->Emit(build)); + ExpEmit yval = EmitKonst(build, xyz[1]->Emit(build)); + assert(xval.RegType == REGT_FLOAT && yval.RegType == REGT_FLOAT); + if (yval.RegNum == xval.RegNum + 1) + { + // The results are already in two continuous registers so just return them as-is. + xval.RegCount++; + return xval; + } + else + { + // The values are not in continuous registers so they need to be copied together now. + ExpEmit out(build, REGT_FLOAT, 2); + build->Emit(OP_MOVEF, out.RegNum, xval.RegNum); + build->Emit(OP_MOVEF, out.RegNum + 1, yval.RegNum); + xval.Free(build); + yval.Free(build); + return out; + } + } + else if (xyz[0]->ValueType == TypeVector2) // vec2+float + { + ExpEmit xyval = xyz[0]->Emit(build); + ExpEmit zval = EmitKonst(build, xyz[1]->Emit(build)); + assert(xyval.RegType == REGT_FLOAT && xyval.RegCount == 2 && zval.RegType == REGT_FLOAT); + if (zval.RegNum == xyval.RegNum + 2) + { + // The results are already in three continuous registers so just return them as-is. + xyval.RegCount++; + return xyval; + } + else + { + // The values are not in continuous registers so they need to be copied together now. + ExpEmit out(build, REGT_FLOAT, 3); + build->Emit(OP_MOVEV2, out.RegNum, xyval.RegNum); + build->Emit(OP_MOVEF, out.RegNum + 2, zval.RegNum); + xyval.Free(build); + zval.Free(build); + return out; + } + } + else // 3*float + { + assert(xyz[2] != nullptr); + ExpEmit xval = EmitKonst(build, xyz[0]->Emit(build)); + ExpEmit yval = EmitKonst(build, xyz[1]->Emit(build)); + ExpEmit zval = EmitKonst(build, xyz[2]->Emit(build)); + assert(xval.RegType == REGT_FLOAT && yval.RegType == REGT_FLOAT && zval.RegType == REGT_FLOAT); + if (yval.RegNum == xval.RegNum + 1 && zval.RegNum == xval.RegNum + 2) + { + // The results are already in three continuous registers so just return them as-is. + xval.RegCount += 2; + return xval; + } + else + { + // The values are not in continuous registers so they need to be copied together now. + ExpEmit out(build, REGT_FLOAT, 3); + //Try to optimize a bit... + if (yval.RegNum == xval.RegNum + 1) + { + build->Emit(OP_MOVEV2, out.RegNum, xval.RegNum); + build->Emit(OP_MOVEF, out.RegNum + 2, zval.RegNum); + } + else if (zval.RegNum == yval.RegNum + 1) + { + build->Emit(OP_MOVEF, out.RegNum, xval.RegNum); + build->Emit(OP_MOVEV2, out.RegNum+1, yval.RegNum); + } + else + { + build->Emit(OP_MOVEF, out.RegNum, xval.RegNum); + build->Emit(OP_MOVEF, out.RegNum + 1, yval.RegNum); + build->Emit(OP_MOVEF, out.RegNum + 2, zval.RegNum); + } + xval.Free(build); + yval.Free(build); + zval.Free(build); + return out; + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + FxBoolCast::FxBoolCast(FxExpression *x, bool needvalue) : FxExpression(EFX_BoolCast, x->ScriptPosition) { @@ -4613,7 +4808,7 @@ ExpEmit FxStructMember::Emit(VMFunctionBuilder *build) } int offsetreg = build->GetConstantInt((int)membervar->Offset); - ExpEmit loc(build, membervar->Type->GetRegType()); + ExpEmit loc(build, membervar->Type->GetRegType(), membervar->Type->GetRegCount()); if (membervar->BitValue == -1) { @@ -7118,6 +7313,7 @@ FxLocalVariableDeclaration::FxLocalVariableDeclaration(PType *type, FName name, ValueType = type; VarFlags = varflags; Name = name; + RegCount = type == TypeVector2 ? 2 : type == TypeVector3 ? 3 : 1; Init = initval == nullptr? nullptr : new FxTypeCast(initval, type, false); } @@ -7139,7 +7335,7 @@ ExpEmit FxLocalVariableDeclaration::Emit(VMFunctionBuilder *build) { if (Init == nullptr) { - RegNum = build->Registers[ValueType->GetRegType()].Get(1); + RegNum = build->Registers[ValueType->GetRegType()].Get(RegCount); } else { @@ -7188,5 +7384,5 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build) { // Release the register after the containing block gets closed assert(RegNum != -1); - build->Registers[ValueType->GetRegType()].Return(RegNum, 1); + build->Registers[ValueType->GetRegType()].Return(RegNum, RegCount); } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index cd93b8894..30401f907 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -193,13 +193,13 @@ struct ExpVal struct ExpEmit { - ExpEmit() : RegNum(0), RegType(REGT_NIL), Konst(false), Fixed(false), Final(false), Target(false) {} - ExpEmit(int reg, int type, bool konst = false, bool fixed = false) : RegNum(reg), RegType(type), Konst(konst), Fixed(fixed), Final(false), Target(false) {} - ExpEmit(VMFunctionBuilder *build, int type); + ExpEmit() : RegNum(0), RegType(REGT_NIL), RegCount(1), Konst(false), Fixed(false), Final(false), Target(false) {} + ExpEmit(int reg, int type, bool konst = false, bool fixed = false) : RegNum(reg), RegType(type), RegCount(1), Konst(konst), Fixed(fixed), Final(false), Target(false) {} + ExpEmit(VMFunctionBuilder *build, int type, int count = 1); void Free(VMFunctionBuilder *build); void Reuse(VMFunctionBuilder *build); - BYTE RegNum, RegType, Konst:1, Fixed:1, Final:1, Target:1; + BYTE RegNum, RegType, RegCount, Konst:1, Fixed:1, Final:1, Target:1; }; enum EFxType @@ -264,6 +264,7 @@ enum EFxType EFX_LocalVariableDeclaration, EFX_SwitchStatement, EFX_CaseStatement, + EFX_VectorInitializer, EFX_COUNT }; @@ -449,6 +450,25 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// +// +//========================================================================== + +class FxVectorInitializer : public FxExpression +{ + FxExpression *xyz[3]; + bool isConst; // gets set to true if all element are const + +public: + FxVectorInitializer(FxExpression *x, FxExpression *y, FxExpression *z, const FScriptPosition &sc); + ~FxVectorInitializer(); + FxExpression *Resolve(FCompileContext&); + + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // @@ -1561,6 +1581,7 @@ class FxLocalVariableDeclaration : public FxExpression FName Name; FxExpression *Init; int VarFlags; + int RegCount; public: int RegNum = -1; diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 5684d5775..c14a8a6e5 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -137,7 +137,7 @@ enum REGT_MULTIREG = 8, // (e.g. a vector) REGT_ADDROF = 32, // used with PARAM: pass address of this register - REGT_NIL = 255 // parameter was omitted + REGT_NIL = 128 // parameter was omitted }; #define RET_FINAL (0x80) // Used with RET and RETI in the destination slot: this is the final return value diff --git a/src/scripting/zscript/ast.cpp b/src/scripting/zscript/ast.cpp index e23fc5a87..e77c631e1 100644 --- a/src/scripting/zscript/ast.cpp +++ b/src/scripting/zscript/ast.cpp @@ -52,7 +52,6 @@ static const char *BuiltInTypeNames[] = "string", "vector2", "vector3", - "vector4", "name", "color", "state", @@ -622,6 +621,16 @@ static void PrintExprTrinary(FLispString &out, ZCC_TreeNode *node) out.Close(); } +static void PrintVectorInitializer(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_VectorInitializer *enode = (ZCC_VectorInitializer *)node; + OpenExprType(out, enode->Operation); + PrintNodes(out, enode->X); + PrintNodes(out, enode->Y); + PrintNodes(out, enode->Z); + out.Close(); +} + static void PrintFuncParam(FLispString &out, ZCC_TreeNode *node) { ZCC_FuncParm *pnode = (ZCC_FuncParm *)node; @@ -889,7 +898,8 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode * PrintFuncDeclarator, PrintDefault, PrintFlagStmt, - PrintPropertyStmt + PrintPropertyStmt, + PrintVectorInitializer, }; FString ZCC_PrintAST(ZCC_TreeNode *root) diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index bbed008dd..173ec27fc 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -945,6 +945,7 @@ func_param_flags(X) ::= func_param_flags(A) OPTIONAL(T). { X.Int = A.Int | ZCC_O %type expr{ZCC_Expression *} %type primary{ZCC_Expression *} +%type vectorinit{ZCC_VectorInitializer*} %type unary_expr{ZCC_Expression *} %type constant{ZCC_ExprConstant *} @@ -966,29 +967,7 @@ primary(X) ::= SUPER(T). X = expr; } primary(X) ::= constant(A). { X = A; /*X-overwrites-A*/ } - -primary(XX) ::= LPAREN expr(A) COMMA expr(B) COMMA expr(C) RPAREN. -{ - NEW_AST_NODE(VectorInitializer, expr, A); - expr->Operation = PEX_Vector; - expr->Type = TypeVector3; - expr->X = A; - expr->Y = B; - expr->Z = C; - XX = expr; -} - - -primary(XX) ::= LPAREN expr(A) COMMA expr(B) RPAREN. -{ - NEW_AST_NODE(VectorInitializer, expr, A); - expr->Operation = PEX_Vector; - expr->Type = TypeVector2; - expr->X = A; - expr->Y = B; - expr->Z = nullptr; - XX = expr; -} +primary(X) ::= vectorinit(A). { X = A; /*X-overwrites-A*/ } primary(X) ::= LPAREN expr(A) RPAREN. { @@ -1039,6 +1018,30 @@ primary(X) ::= SCOPE primary(B). X = expr2; } */ + +vectorinit(XX) ::= LPAREN expr(A) COMMA expr(B) COMMA expr(C) RPAREN. [DOT] +{ + NEW_AST_NODE(VectorInitializer, expr, A); + expr->Operation = PEX_Vector; + expr->Type = TypeVector3; + expr->X = A; + expr->Y = B; + expr->Z = C; + XX = expr; +} + + +vectorinit(XX) ::= LPAREN expr(A) COMMA expr(B) RPAREN. [DOT] +{ + NEW_AST_NODE(VectorInitializer, expr, A); + expr->Operation = PEX_Vector; + expr->Type = TypeVector2; + expr->X = A; + expr->Y = B; + expr->Z = nullptr; + XX = expr; +} + /*----- Unary Expressions -----*/ unary_expr(X) ::= primary(X). diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index dc638de0f..f1a06d584 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -1387,11 +1387,6 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n retval = TypeVector3; break; - case ZCC_Vector4: - // This has almost no use, so we really shouldn't bother. - Error(field, "vector<4> not implemented for %s", name.GetChars()); - return TypeError; - case ZCC_State: retval = TypeState; break; @@ -2710,6 +2705,15 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) return new FxConditional(condition, left, right); } + case AST_VectorInitializer: + { + auto vecini = static_cast(ast); + auto xx = ConvertNode(vecini->X); + auto yy = ConvertNode(vecini->Y); + auto zz = ConvertNode(vecini->Z); + return new FxVectorInitializer(xx, yy, zz, *ast); + } + case AST_LocalVarStmt: { auto loc = static_cast(ast); diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index ef4a2ac41..84bebff40 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -301,7 +301,8 @@ static void DoParse(int lumpnum) parser = ZCCParseAlloc(malloc); ZCCParseState state; -#if 0 // this costs a lot of time and should only be activated when it's really needed. +//#define TRACE +#ifdef TRACE // this costs a lot of time and should only be activated when it's really needed. FILE *f = fopen("trace.txt", "w"); char prompt = '\0'; ZCCParseTrace(f, &prompt); @@ -335,7 +336,7 @@ static void DoParse(int lumpnum) I_Error("%d errors while parsing %s", FScriptPosition::ErrorCounter, Wads.GetLumpFullPath(lumpnum).GetChars()); } -#if 0 +#ifdef TRACE if (f != NULL) { fclose(f); diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index dafdb93e5..0889d1d37 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -120,7 +120,6 @@ enum EZCCBuiltinType ZCC_String, ZCC_Vector2, ZCC_Vector3, - ZCC_Vector4, ZCC_Name, ZCC_Color, // special types for ZDoom.