From 9f99ca478890b1b50698233a84888b8dcdb5de27 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 21 Oct 2016 01:12:54 +0200 Subject: [PATCH] - process most of the remaining statement types. - extend assignment operations to handle local variables (untested.) - make the implicit function arguments read only. --- src/dobjtype.cpp | 56 ++++++++++ src/dobjtype.h | 9 +- src/scripting/codegeneration/codegen.cpp | 135 +++++++++++++++++++---- src/scripting/codegeneration/codegen.h | 25 ++++- src/scripting/thingdef.cpp | 6 +- src/scripting/vm/vmbuilder.cpp | 5 +- src/scripting/vm/vmexec.h | 20 ++-- src/scripting/zscript/zcc_compile.cpp | 63 ++++++++++- 8 files changed, 277 insertions(+), 42 deletions(-) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index f25e592f2f..ded832f2df 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -500,6 +500,18 @@ int PType::GetLoadOp() const return OP_NOP; } +//========================================================================== +// +// PType :: GetMoveOp +// +//========================================================================== + +int PType::GetMoveOp() const +{ + assert(0 && "Cannot move this type"); + return OP_NOP; +} + //========================================================================== // // PType :: GetRegType @@ -974,6 +986,17 @@ int PInt::GetLoadOp() const } } +//========================================================================== +// +// PInt :: GetLoadOp +// +//========================================================================== + +int PInt::GetMoveOp() const +{ + return OP_MOVE; +} + //========================================================================== // // PInt :: GetRegType @@ -1271,6 +1294,17 @@ int PFloat::GetLoadOp() const return OP_NOP; } +//========================================================================== +// +// PFloat :: GetMoveOp +// +//========================================================================== + +int PFloat::GetMoveOp() const +{ + return OP_MOVEF; +} + //========================================================================== // // PFloat :: GetRegType @@ -1540,6 +1574,17 @@ int PStatePointer::GetLoadOp() const return OP_LP; } +//========================================================================== +// +// PStatePointer :: GetMoveOp +// +//========================================================================== + +int PStatePointer::GetMoveOp() const +{ + return OP_MOVEA; +} + //========================================================================== // // PStatePointer :: GetRegType @@ -1627,6 +1672,17 @@ int PPointer::GetLoadOp() const return PointedType->IsKindOf(RUNTIME_CLASS(PClass)) ? OP_LO : OP_LP; } +//========================================================================== +// +// PPointer :: GetMoveOp +// +//========================================================================== + +int PPointer::GetMoveOp() const +{ + return OP_MOVEA; +} + //========================================================================== // // PPointer :: GetRegType diff --git a/src/dobjtype.h b/src/dobjtype.h index fd6e078eab..4a15078fd2 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -28,7 +28,7 @@ enum VARF_Final = (1<<9), // Function may not be overridden in subclasses VARF_In = (1<<10), VARF_Out = (1<<11), - VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare when checking function signatures) + VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures) VARF_Static = (1<<13), // static class data (by necessity read only.) }; @@ -272,6 +272,9 @@ public: // Gets the opcode to load from memory to a register virtual int GetLoadOp() const; + // Gets the opcode to move from register to another register + virtual int GetMoveOp() const; + // Gets the register type for this type virtual int GetRegType() const; @@ -409,6 +412,7 @@ public: virtual double GetValueFloat(void *addr) const; virtual int GetStoreOp() const; virtual int GetLoadOp() const; + virtual int GetMoveOp() const; virtual int GetRegType() const; bool Unsigned; @@ -438,6 +442,7 @@ public: virtual double GetValueFloat(void *addr) const; virtual int GetStoreOp() const; virtual int GetLoadOp() const; + virtual int GetMoveOp() const; virtual int GetRegType() const; protected: PFloat(); @@ -516,6 +521,7 @@ public: virtual int GetStoreOp() const; virtual int GetLoadOp() const; + virtual int GetMoveOp() const; virtual int GetRegType() const; }; @@ -530,6 +536,7 @@ public: virtual int GetStoreOp() const; virtual int GetLoadOp() const; + virtual int GetMoveOp() const; virtual int GetRegType() const; virtual bool IsMatch(intptr_t id1, intptr_t id2) const; diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 9b6248c88e..d3e7ef0299 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -160,6 +160,18 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos) } } +FxLocalVariableDeclaration *FCompileContext::FindLocalVariable(FName name) +{ + if (Block == nullptr) + { + return nullptr; + } + else + { + return Block->FindLocalVariable(name, *this); + } +} + //========================================================================== // // ExpEmit @@ -1611,9 +1623,13 @@ ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build) int zero = build->GetConstantInt(0); int regtype = ValueType->GetRegType(); ExpEmit pointer = Base->Emit(build); + ExpEmit value = pointer; - ExpEmit value(build, regtype); - build->Emit(ValueType->GetLoadOp(), value.RegNum, pointer.RegNum, zero); + if (!pointer.Target) + { + value = ExpEmit(build, regtype); + build->Emit(ValueType->GetLoadOp(), value.RegNum, pointer.RegNum, zero); + } if (regtype == REGT_INT) { @@ -1624,7 +1640,10 @@ ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build) build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, value.RegNum, value.RegNum, build->GetConstantFloat(1.)); } - build->Emit(ValueType->GetStoreOp(), pointer.RegNum, value.RegNum, zero); + if (!pointer.Target) + { + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, value.RegNum, zero); + } if (AddressRequested) { @@ -1690,9 +1709,13 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) int zero = build->GetConstantInt(0); int regtype = ValueType->GetRegType(); ExpEmit pointer = Base->Emit(build); + ExpEmit out = pointer; - ExpEmit out(build, regtype); - build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero); + if (!pointer.Target) + { + out = ExpEmit(build, regtype); + build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero); + } ExpEmit assign(build, regtype); if (regtype == REGT_INT) @@ -1704,7 +1727,10 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, assign.RegNum, out.RegNum, build->GetConstantFloat(1.)); } - build->Emit(ValueType->GetStoreOp(), pointer.RegNum, assign.RegNum, zero); + if (!pointer.Target) + { + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, assign.RegNum, zero); + } pointer.Free(build); assign.Free(build); @@ -1781,6 +1807,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx) ExpEmit FxAssign::Emit(VMFunctionBuilder *build) { + static const BYTE loadops[] = { OP_NOP, OP_LK, OP_LKF, OP_LKS, OP_LKP }; assert(ValueType == Base->ValueType && IsNumeric()); assert(ValueType->GetRegType() == Right->ValueType->GetRegType()); @@ -1788,16 +1815,31 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build) Address = pointer; ExpEmit result = Right->Emit(build); - - if (result.Konst) - { - ExpEmit temp(build, result.RegType); - build->Emit(result.RegType == REGT_FLOAT ? OP_LKF : OP_LK, temp.RegNum, result.RegNum); - result.Free(build); - result = temp; - } + assert(result.RegType <= REGT_TYPE); - build->Emit(ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0)); + if (pointer.Target) + { + if (result.Konst) + { + build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum); + } + else + { + build->Emit(Right->ValueType->GetMoveOp(), pointer.RegNum, result.RegNum); + } + } + else + { + if (result.Konst) + { + ExpEmit temp(build, result.RegType); + build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum); + result.Free(build); + result = temp; + } + + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0)); + } if (AddressRequested) { @@ -1837,9 +1879,16 @@ ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build) { assert(ValueType = Assignment->ValueType); ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it - ExpEmit out(build, ValueType->GetRegType()); - build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0)); - return out; + if (!pointer.Target) + { + ExpEmit out(build, ValueType->GetRegType()); + build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0)); + return out; + } + else + { + return pointer; + } } //========================================================================== @@ -3858,8 +3907,15 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) CHECKRESOLVED(); + // Local variables have highest priority. + FxLocalVariableDeclaration *local = ctx.FindLocalVariable(Identifier); + if (local != nullptr) + { + auto x = new FxLocalVariable(local, ScriptPosition); + delete this; + return x->Resolve(ctx); + } // Ugh, the horror. Constants need to be taken from the owning class, but members from the self class to catch invalid accesses here... - // see if the current class (if valid) defines something with this name. PSymbolTable *symtbl; if ((sym = ctx.FindInClass(Identifier, symtbl)) != nullptr) @@ -3959,6 +4015,40 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) } +//========================================================================== +// +// +// +//========================================================================== + +FxLocalVariable::FxLocalVariable(FxLocalVariableDeclaration *var, const FScriptPosition &sc) + : FxExpression(sc) +{ + Variable = var; + AddressRequested = false; +} + +FxExpression *FxLocalVariable::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + return this; +} + +bool FxLocalVariable::RequestAddress(bool *writable) +{ + AddressRequested = true; + if (writable != nullptr) *writable = !(Variable->VarFlags & VARF_ReadOnly); + return true; +} + +ExpEmit FxLocalVariable::Emit(VMFunctionBuilder *build) +{ + ExpEmit ret(Variable->RegNum, Variable->ValueType->GetRegType(), false, true); + if (AddressRequested) ret.Target = true; + return ret; +} + + //========================================================================== // // @@ -3998,9 +4088,7 @@ FxExpression *FxSelf::Resolve(FCompileContext& ctx) ExpEmit FxSelf::Emit(VMFunctionBuilder *build) { // self is always the first pointer passed to the function - ExpEmit me(0, REGT_POINTER); - me.Fixed = true; - return me; + return ExpEmit(0, REGT_POINTER, false, true); } @@ -6238,10 +6326,11 @@ ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build) // //========================================================================== -FxLocalVariableDeclaration::FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, const FScriptPosition &p) +FxLocalVariableDeclaration::FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p) :FxExpression(p) { ValueType = type; + VarFlags = varflags; Name = name; Init = initval == nullptr? nullptr : new FxTypeCast(initval, type, false); } diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index c16c45f42e..7a69f39896 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -85,6 +85,7 @@ struct FCompileContext void HandleJumps(int token, FxExpression *handler); void CheckReturn(PPrototype *proto, FScriptPosition &pos); + FxLocalVariableDeclaration *FindLocalVariable(FName name); }; //========================================================================== @@ -198,7 +199,7 @@ struct ExpEmit void Free(VMFunctionBuilder *build); void Reuse(VMFunctionBuilder *build); - BYTE RegNum, RegType, Konst:1, Fixed:1, Final:1; + BYTE RegNum, RegType, Konst:1, Fixed:1, Final:1, Target:1; }; //========================================================================== @@ -964,6 +965,24 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxLocalVariable +// +//========================================================================== + +class FxLocalVariable : public FxExpression +{ +public: + FxLocalVariableDeclaration *Variable; + bool AddressRequested; + + FxLocalVariable(FxLocalVariableDeclaration*, const FScriptPosition&); + FxExpression *Resolve(FCompileContext&); + bool RequestAddress(bool *writable); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxSelf @@ -1382,13 +1401,15 @@ public: class FxLocalVariableDeclaration : public FxExpression { friend class FxCompoundStatement; + friend class FxLocalVariable; FName Name; FxExpression *Init; + int VarFlags; public: int RegNum = -1; - FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, const FScriptPosition &p); + FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); void Release(VMFunctionBuilder *build); diff --git a/src/scripting/thingdef.cpp b/src/scripting/thingdef.cpp index fc281e8e8a..7fcb0ce39d 100644 --- a/src/scripting/thingdef.cpp +++ b/src/scripting/thingdef.cpp @@ -90,7 +90,7 @@ void SetImplicitArgs(TArray *args, TArray *argflags, TArrayPush(NewPointer(cls)); - if (argflags != nullptr) argflags->Push(VARF_Implicit); + if (argflags != nullptr) argflags->Push(VARF_Implicit | VARF_ReadOnly); if (argnames != nullptr) argnames->Push(NAME_self); } if (funcflags & VARF_Action) @@ -111,8 +111,8 @@ void SetImplicitArgs(TArray *args, TArray *argflags, TArrayPush(VARF_Implicit); - argflags->Push(VARF_Implicit); + argflags->Push(VARF_Implicit | VARF_ReadOnly); + argflags->Push(VARF_Implicit | VARF_ReadOnly); } if (argnames != nullptr) { diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 5e5ce85db1..0ba6974950 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -693,8 +693,9 @@ void FFunctionBuildList::Build() { auto type = item.Func->Variants[0].Proto->ArgumentTypes[i]; auto name = item.Func->Variants[0].ArgNames[i]; - // this won't get resolved and won't get emitted. This is only needed so that the code generator can retrieve the necessary info to do its work. - auto local = new FxLocalVariableDeclaration(type, name, nullptr, FScriptPosition()); + auto flags = item.Func->Variants[0].ArgFlags[i]; + // this won't get resolved and won't get emitted. It is only needed so that the code generator can retrieve the necessary info about this argument to do its work. + auto local = new FxLocalVariableDeclaration(type, name, nullptr, flags, FScriptPosition()); local->RegNum = buildit.Registers[type->GetRegType()].Get(1); ctx.FunctionArgs.Push(local); } diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 9dbea7c51b..db4afa05ac 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -194,7 +194,7 @@ begin: ASSERTF(a+2); ASSERTA(B); ASSERTKD(C); GETADDR(PB,KC,X_READ_NIL); { - float *v = (float *)ptr; + auto v = (double *)ptr; reg.f[a] = v[0]; reg.f[a+1] = v[1]; reg.f[a+2] = v[2]; @@ -204,7 +204,7 @@ begin: ASSERTF(a+2); ASSERTA(B); ASSERTD(C); GETADDR(PB,RC,X_READ_NIL); { - float *v = (float *)ptr; + auto v = (double *)ptr; reg.f[a] = v[0]; reg.f[a+1] = v[1]; reg.f[a+2] = v[2]; @@ -290,20 +290,20 @@ begin: ASSERTA(a); ASSERTF(B+2); ASSERTKD(C); GETADDR(PA,KC,X_WRITE_NIL); { - float *v = (float *)ptr; - v[0] = (float)reg.f[B]; - v[1] = (float)reg.f[B+1]; - v[2] = (float)reg.f[B+2]; + auto v = (double *)ptr; + v[0] = reg.f[B]; + v[1] = reg.f[B+1]; + v[2] = reg.f[B+2]; } NEXTOP; OP(SV_R): ASSERTA(a); ASSERTF(B+2); ASSERTD(C); GETADDR(PA,RC,X_WRITE_NIL); { - float *v = (float *)ptr; - v[0] = (float)reg.f[B]; - v[1] = (float)reg.f[B+1]; - v[2] = (float)reg.f[B+2]; + auto v = (double *)ptr; + v[0] = reg.f[B]; + v[1] = reg.f[B+1]; + v[2] = reg.f[B+2]; } NEXTOP; OP(SBIT): diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 88486d9c35..d5b3a27050 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -42,6 +42,7 @@ #include "cmdlib.h" #include "m_alloc.h" #include "zcc_parser.h" +#include "zcc-parse.h" #include "zcc_compile.h" #include "v_text.h" #include "p_lnspec.h" @@ -2344,11 +2345,42 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) // The function name is a simple identifier. return new FxFunctionCall(static_cast(fcall->Function)->Identifier, NAME_None, ConvertNodeList(fcall->Parameters), *ast); + // not yet done + case AST_ExprTypeRef: + case AST_SwitchStmt: + case AST_CaseStmt: case AST_ExprMemberAccess: // calling a class member through its pointer // todo. break; + case AST_AssignStmt: + { + auto assign = static_cast(ast); + switch (assign->AssignOp) + { + case ZCC_EQ: + // this ignores multi-assign statements (these should probably be disabled in the grammar.) + return new FxAssign(ConvertNode(assign->Dests), ConvertNode(assign->Sources)); + + case ZCC_MULEQ: + case ZCC_DIVEQ: + case ZCC_MODEQ: + case ZCC_ADDEQ: + case ZCC_SUBEQ: + case ZCC_LSHEQ: + case ZCC_RSHEQ: + case ZCC_ANDEQ: + case ZCC_OREQ: + case ZCC_XOREQ: + //break; + default: + Error(ast, "Invalid assign statement"); + + } + break; + } + case AST_ExprBinary: // Array syntax for randoms. They are internally stored as ExprBinary with both an identifier on the left and right side. if (fcall->Function->Operation == PEX_ArrayAccess) @@ -2546,7 +2578,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) { val = node->Init ? ConvertNode(node->Init) : nullptr; } - list->Add(new FxLocalVariableDeclaration(type, node->Name, val, *node)); + list->Add(new FxLocalVariableDeclaration(type, node->Name, val, 0, *node)); // todo: Handle flags in the grammar. } node = static_cast(node->SiblingNext); @@ -2576,6 +2608,35 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) } } + case AST_BreakStmt: + case AST_ContinueStmt: + return new FxJumpStatement(ast->NodeType == AST_BreakStmt ? TK_Break : TK_Continue, *ast); + + case AST_IfStmt: + { + auto iff = static_cast(ast); + return new FxIfStatement(ConvertNode(iff->Condition), ConvertNode(iff->TruePath), ConvertNode(iff->FalsePath), *ast); + } + + case AST_IterationStmt: + { + auto iter = static_cast(ast); + if (iter->CheckAt == ZCC_IterationStmt::End) + { + assert(iter->LoopBumper == nullptr); + return new FxDoWhileLoop(ConvertNode(iter->LoopCondition), ConvertNode(iter->LoopStatement), *ast); + } + else if (iter->LoopBumper != nullptr) + { + return new FxForLoop(nullptr, ConvertNode(iter->LoopCondition), ConvertNode(iter->LoopBumper), ConvertNode(iter->LoopStatement), *ast); + } + else + { + return new FxWhileLoop(ConvertNode(iter->LoopCondition), ConvertNode(iter->LoopStatement), *ast); + } + } + + case AST_CompoundStmt: { auto x = new FxCompoundStatement(*ast);