diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 6dac05d7b..7be1b9cf2 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -5402,7 +5402,13 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx) FxLocalVariableDeclaration *local = ctx.FindLocalVariable(Identifier); if (local != nullptr) { - if (local->ValueType->GetRegType() != REGT_NIL) + if (local->ExprType == EFX_StaticArray) + { + auto x = new FxStaticArrayVariable(local, ScriptPosition); + delete this; + return x->Resolve(ctx); + } + else if (local->ValueType->GetRegType() != REGT_NIL) { auto x = new FxLocalVariable(local, ScriptPosition); delete this; @@ -5693,6 +5699,38 @@ ExpEmit FxLocalVariable::Emit(VMFunctionBuilder *build) } +//========================================================================== +// +// +// +//========================================================================== + +FxStaticArrayVariable::FxStaticArrayVariable(FxLocalVariableDeclaration *var, const FScriptPosition &sc) + : FxExpression(EFX_StaticArrayVariable, sc) +{ + Variable = static_cast(var); + ValueType = Variable->ValueType; +} + +FxExpression *FxStaticArrayVariable::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + return this; +} + +bool FxStaticArrayVariable::RequestAddress(FCompileContext &ctx, bool *writable) +{ + AddressRequested = true; + if (writable != nullptr) *writable = false; + return true; +} + +ExpEmit FxStaticArrayVariable::Emit(VMFunctionBuilder *build) +{ + // returns the first const register for this array + return ExpEmit(Variable->StackOffset, Variable->ElementType->GetRegType(), true, false); +} + //========================================================================== // @@ -6357,6 +6395,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) ExpEmit start = Array->Emit(build); PArray *const arraytype = static_cast(Array->ValueType); + /* what was this for? if (start.Konst) { ExpEmit tmpstart(build, REGT_POINTER); @@ -6364,16 +6403,17 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) start.Free(build); start = tmpstart; } + */ if (index->isConstant()) { unsigned indexval = static_cast(index)->GetValue().GetInt(); assert(indexval < arraytype->ElementCount && "Array index out of bounds"); - indexval *= arraytype->ElementSize; if (AddressRequested) { if (indexval != 0) { + indexval *= arraytype->ElementSize; if (!start.Fixed) { build->Emit(OP_ADDA_RK, start.RegNum, start.RegNum, build->GetConstantInt(indexval)); @@ -6389,61 +6429,90 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) } return start; } - else + else if (!start.Konst) { start.Free(build); ExpEmit dest(build, ValueType->GetRegType()); - build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, start.RegNum, build->GetConstantInt(indexval)); + build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, start.RegNum, build->GetConstantInt(indexval* arraytype->ElementSize)); + return dest; + } + else + { + static int LK_Ops[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP }; + assert(start.RegType == ValueType->GetRegType()); + ExpEmit dest(build, start.RegType); + build->Emit(LK_Ops[start.RegType], dest.RegNum, start.RegNum + indexval); return dest; } } else { ExpEmit indexv(index->Emit(build)); - ExpEmit indexwork = indexv.Fixed ? ExpEmit(build, indexv.RegType) : indexv; build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount); - int shiftbits = 0; - while (1u << shiftbits < arraytype->ElementSize) - { - shiftbits++; - } - if (1u << shiftbits == arraytype->ElementSize) + if (!start.Konst) { - if (shiftbits > 0) + ExpEmit indexwork = indexv.Fixed ? ExpEmit(build, indexv.RegType) : indexv; + int shiftbits = 0; + while (1u << shiftbits < arraytype->ElementSize) { - build->Emit(OP_SLL_RI, indexwork.RegNum, indexv.RegNum, shiftbits); + shiftbits++; } - } - else - { - // A shift won't do, so use a multiplication - build->Emit(OP_MUL_RK, indexwork.RegNum, indexv.RegNum, build->GetConstantInt(arraytype->ElementSize)); - } - - indexwork.Free(build); - if (AddressRequested) - { - if (!start.Fixed) + if (1u << shiftbits == arraytype->ElementSize) { - build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexwork.RegNum); + if (shiftbits > 0) + { + build->Emit(OP_SLL_RI, indexwork.RegNum, indexv.RegNum, shiftbits); + } + } + else + { + // A shift won't do, so use a multiplication + build->Emit(OP_MUL_RK, indexwork.RegNum, indexv.RegNum, build->GetConstantInt(arraytype->ElementSize)); + } + indexwork.Free(build); + + if (AddressRequested) + { + if (!start.Fixed) + { + build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexwork.RegNum); + } + else + { + start.Free(build); + // do not clobber local variables. + ExpEmit temp(build, start.RegType); + build->Emit(OP_ADDA_RR, temp.RegNum, start.RegNum, indexwork.RegNum); + start = temp; + } + return start; } else { start.Free(build); - // do not clobber local variables. - ExpEmit temp(build, start.RegType); - build->Emit(OP_ADDA_RR, temp.RegNum, start.RegNum, indexwork.RegNum); - start = temp; + ExpEmit dest(build, ValueType->GetRegType()); + // added 1 to use the *_R version that takes the offset from a register + build->Emit(arraytype->ElementType->GetLoadOp() + 1, dest.RegNum, start.RegNum, indexwork.RegNum); + return dest; } - return start; } else { - start.Free(build); - ExpEmit dest(build, ValueType->GetRegType()); - // added 1 to use the *_R version that takes the offset from a register - build->Emit(arraytype->ElementType->GetLoadOp() + 1, dest.RegNum, start.RegNum, indexwork.RegNum); + static int LKR_Ops[] = { OP_LK_R, OP_LKF_R, OP_LKS_R, OP_LKP_R }; + assert(start.RegType == ValueType->GetRegType()); + ExpEmit dest(build, start.RegType); + if (start.RegNum <= 255) + { + // Since large constant tables are the exception, the constant component in C is an immediate value here. + build->Emit(LKR_Ops[start.RegType], dest.RegNum, indexv.RegNum, start.RegNum); + } + else + { + build->Emit(OP_ADD_RK, indexv.RegNum, indexv.RegNum, build->GetConstantInt(start.RegNum)); + build->Emit(LKR_Ops[start.RegType], dest.RegNum, indexv.RegNum, 0); + } + indexv.Free(build); return dest; } } @@ -9241,3 +9310,82 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build) // Stack space will not be released because that would make controlled destruction impossible. // For that all local stack variables need to live for the entire execution of a function. } + + +FxStaticArray::FxStaticArray(PType *type, FName name, FArgumentList &args, const FScriptPosition &pos) + : FxLocalVariableDeclaration(NewArray(type, args.Size()), name, nullptr, VARF_Static|VARF_ReadOnly, pos) +{ + ElementType = type; + ExprType = EFX_StaticArray; + values = std::move(args); +} + +FxExpression *FxStaticArray::Resolve(FCompileContext &ctx) +{ + bool fail = false; + for (unsigned i = 0; i < values.Size(); i++) + { + values[i] = new FxTypeCast(values[i], ElementType, false); + values[i] = values[i]->Resolve(ctx); + if (values[i] == nullptr) fail = true; + else if (!values[i]->isConstant()) + { + ScriptPosition.Message(MSG_ERROR, "Initializer must be constant"); + fail = true; + } + } + if (fail) + { + delete this; + return nullptr; + } + if (ElementType->GetRegType() == REGT_NIL) + { + ScriptPosition.Message(MSG_ERROR, "Invalid type for constant array"); + delete this; + return nullptr; + } + + ctx.Block->LocalVars.Push(this); + return this; +} + +ExpEmit FxStaticArray::Emit(VMFunctionBuilder *build) +{ + switch (ElementType->GetRegType()) + { + default: + assert(false && "Invalid register type"); + break; + + case REGT_INT: + { + TArray cvalues; + for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetInt()); + StackOffset = build->AllocConstantsInt(cvalues.Size(), &cvalues[0]); + break; + } + case REGT_FLOAT: + { + TArray cvalues; + for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetFloat()); + StackOffset = build->AllocConstantsFloat(cvalues.Size(), &cvalues[0]); + break; + } + case REGT_STRING: + { + TArray cvalues; + for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetString()); + StackOffset = build->AllocConstantsString(cvalues.Size(), &cvalues[0]); + break; + } + case REGT_POINTER: + { + TArray cvalues; + for (auto v : values) cvalues.Push(static_cast(v)->GetValue().GetPointer()); + StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() == OP_LO ? ATAG_OBJECT : ATAG_GENERIC); + break; + } + } + return ExpEmit(); +} diff --git a/src/scripting/codegeneration/codegen.h b/src/scripting/codegeneration/codegen.h index 03b256970..7f588a0eb 100644 --- a/src/scripting/codegeneration/codegen.h +++ b/src/scripting/codegeneration/codegen.h @@ -282,6 +282,8 @@ enum EFxType EFX_Super, EFX_StackVariable, EFX_MultiAssign, + EFX_StaticArray, + EFX_StaticArrayVariable, EFX_COUNT }; @@ -1308,6 +1310,25 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxLocalVariable +// +//========================================================================== +class FxStaticArray; + +class FxStaticArrayVariable : public FxExpression +{ +public: + FxStaticArray *Variable; + bool AddressRequested; + + FxStaticArrayVariable(FxLocalVariableDeclaration*, const FScriptPosition&); + FxExpression *Resolve(FCompileContext&); + bool RequestAddress(FCompileContext &ctx, bool *writable); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxSelf @@ -1529,6 +1550,7 @@ class FxCompoundStatement : public FxSequence FxCompoundStatement *Outer = nullptr; friend class FxLocalVariableDeclaration; + friend class FxStaticArray; friend class FxMultiAssign; public: @@ -1841,6 +1863,7 @@ class FxLocalVariableDeclaration : public FxExpression { friend class FxCompoundStatement; friend class FxLocalVariable; + friend class FxStaticArrayVariable; FName Name; FxExpression *Init; @@ -1859,4 +1882,25 @@ public: }; +//========================================================================== +// +// +// +//========================================================================== + +class FxStaticArray : public FxLocalVariableDeclaration +{ + friend class FxStaticArrayVariable; + + PType *ElementType; + FArgumentList values; + +public: + + FxStaticArray(PType *type, FName name, FArgumentList &args, const FScriptPosition &pos); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + + #endif diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 721ff5fab..042753d32 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -45,10 +45,6 @@ VMFunctionBuilder::VMFunctionBuilder(int numimplicits) { - NumIntConstants = 0; - NumFloatConstants = 0; - NumAddressConstants = 0; - NumStringConstants = 0; MaxParam = 0; ActiveParam = 0; NumImplicits = numimplicits; @@ -74,25 +70,25 @@ VMFunctionBuilder::~VMFunctionBuilder() void VMFunctionBuilder::MakeFunction(VMScriptFunction *func) { - func->Alloc(Code.Size(), NumIntConstants, NumFloatConstants, NumStringConstants, NumAddressConstants); + func->Alloc(Code.Size(), IntConstantList.Size(), FloatConstantList.Size(), StringConstantList.Size(), AddressConstantList.Size()); // Copy code block. memcpy(func->Code, &Code[0], Code.Size() * sizeof(VMOP)); // Create constant tables. - if (NumIntConstants > 0) + if (IntConstantList.Size() > 0) { FillIntConstants(func->KonstD); } - if (NumFloatConstants > 0) + if (FloatConstantList.Size() > 0) { FillFloatConstants(func->KonstF); } - if (NumAddressConstants > 0) + if (AddressConstantList.Size() > 0) { FillAddressConstants(func->KonstA, func->KonstATags()); } - if (NumStringConstants > 0) + if (StringConstantList.Size() > 0) { FillStringConstants(func->KonstS); } @@ -118,13 +114,7 @@ void VMFunctionBuilder::MakeFunction(VMScriptFunction *func) void VMFunctionBuilder::FillIntConstants(int *konst) { - TMapIterator it(IntConstants); - TMap::Pair *pair; - - while (it.NextPair(pair)) - { - konst[pair->Value] = pair->Key; - } + memcpy(konst, &IntConstantList[0], sizeof(int) * IntConstantList.Size()); } //========================================================================== @@ -135,13 +125,7 @@ void VMFunctionBuilder::FillIntConstants(int *konst) void VMFunctionBuilder::FillFloatConstants(double *konst) { - TMapIterator it(FloatConstants); - TMap::Pair *pair; - - while (it.NextPair(pair)) - { - konst[pair->Value] = pair->Key; - } + memcpy(konst, &FloatConstantList[0], sizeof(double) * FloatConstantList.Size()); } //========================================================================== @@ -152,14 +136,8 @@ void VMFunctionBuilder::FillFloatConstants(double *konst) void VMFunctionBuilder::FillAddressConstants(FVoidObj *konst, VM_ATAG *tags) { - TMapIterator it(AddressConstants); - TMap::Pair *pair; - - while (it.NextPair(pair)) - { - konst[pair->Value.KonstNum].v = pair->Key; - tags[pair->Value.KonstNum] = pair->Value.Tag; - } + memcpy(konst, &AddressConstantList[0], sizeof(void*) * AddressConstantList.Size()); + memcpy(tags, &AtagConstantList[0], sizeof(VM_ATAG) * AtagConstantList.Size()); } //========================================================================== @@ -170,12 +148,9 @@ void VMFunctionBuilder::FillAddressConstants(FVoidObj *konst, VM_ATAG *tags) void VMFunctionBuilder::FillStringConstants(FString *konst) { - TMapIterator it(StringConstants); - TMap::Pair *pair; - - while (it.NextPair(pair)) + for (auto &s : StringConstantList) { - konst[pair->Value] = pair->Key; + *konst++ = s; } } @@ -183,22 +158,21 @@ void VMFunctionBuilder::FillStringConstants(FString *konst) // // VMFunctionBuilder :: GetConstantInt // -// Returns a constant register initialized with the given value, or -1 if -// there were no more constants free. +// Returns a constant register initialized with the given value. // //========================================================================== -int VMFunctionBuilder::GetConstantInt(int val) +unsigned VMFunctionBuilder::GetConstantInt(int val) { - int *locp = IntConstants.CheckKey(val); + unsigned int *locp = IntConstantMap.CheckKey(val); if (locp != NULL) { return *locp; } else { - int loc = NumIntConstants++; - IntConstants.Insert(val, loc); + unsigned loc = IntConstantList.Push(val); + IntConstantMap.Insert(val, loc); return loc; } } @@ -207,22 +181,21 @@ int VMFunctionBuilder::GetConstantInt(int val) // // VMFunctionBuilder :: GetConstantFloat // -// Returns a constant register initialized with the given value, or -1 if -// there were no more constants free. +// Returns a constant register initialized with the given value. // //========================================================================== -int VMFunctionBuilder::GetConstantFloat(double val) +unsigned VMFunctionBuilder::GetConstantFloat(double val) { - int *locp = FloatConstants.CheckKey(val); + unsigned *locp = FloatConstantMap.CheckKey(val); if (locp != NULL) { return *locp; } else { - int loc = NumFloatConstants++; - FloatConstants.Insert(val, loc); + unsigned loc = FloatConstantList.Push(val); + FloatConstantMap.Insert(val, loc); return loc; } } @@ -231,22 +204,21 @@ int VMFunctionBuilder::GetConstantFloat(double val) // // VMFunctionBuilder :: GetConstantString // -// Returns a constant register initialized with the given value, or -1 if -// there were no more constants free. +// Returns a constant register initialized with the given value. // //========================================================================== -int VMFunctionBuilder::GetConstantString(FString val) +unsigned VMFunctionBuilder::GetConstantString(FString val) { - int *locp = StringConstants.CheckKey(val); + unsigned *locp = StringConstantMap.CheckKey(val); if (locp != NULL) { return *locp; } else { - int loc = NumStringConstants++; - StringConstants.Insert(val, loc); + int loc = StringConstantList.Push(val); + StringConstantMap.Insert(val, loc); return loc; } } @@ -260,13 +232,13 @@ int VMFunctionBuilder::GetConstantString(FString val) // //========================================================================== -int VMFunctionBuilder::GetConstantAddress(void *ptr, VM_ATAG tag) +unsigned VMFunctionBuilder::GetConstantAddress(void *ptr, VM_ATAG tag) { if (ptr == NULL) { // Make all NULL pointers generic. (Or should we allow typed NULLs?) tag = ATAG_GENERIC; } - AddrKonst *locp = AddressConstants.CheckKey(ptr); + AddrKonst *locp = AddressConstantMap.CheckKey(ptr); if (locp != NULL) { // There should only be one tag associated with a memory location. @@ -275,12 +247,71 @@ int VMFunctionBuilder::GetConstantAddress(void *ptr, VM_ATAG tag) } else { - AddrKonst loc = { NumAddressConstants++, tag }; - AddressConstants.Insert(ptr, loc); + unsigned locc = AddressConstantList.Push(ptr); + AtagConstantList.Push(tag); + + AddrKonst loc = { locc, tag }; + AddressConstantMap.Insert(ptr, loc); return loc.KonstNum; } } +//========================================================================== +// +// VMFunctionBuilder :: AllocConstants* +// +// Returns a range of constant register initialized with the given values. +// +//========================================================================== + +unsigned VMFunctionBuilder::AllocConstantsInt(unsigned count, int *values) +{ + unsigned addr = IntConstantList.Reserve(count); + memcpy(&IntConstantList[addr], values, count * sizeof(int)); + for (unsigned i = 0; i < count; i++) + { + IntConstantMap.Insert(values[i], addr + i); + } + return addr; +} + +unsigned VMFunctionBuilder::AllocConstantsFloat(unsigned count, double *values) +{ + unsigned addr = FloatConstantList.Reserve(count); + memcpy(&FloatConstantList[addr], values, count * sizeof(double)); + for (unsigned i = 0; i < count; i++) + { + FloatConstantMap.Insert(values[i], addr + i); + } + return addr; +} + +unsigned VMFunctionBuilder::AllocConstantsAddress(unsigned count, void **ptrs, VM_ATAG tag) +{ + unsigned addr = AddressConstantList.Reserve(count); + AtagConstantList.Reserve(count); + memcpy(&AddressConstantList[addr], ptrs, count * sizeof(void *)); + for (unsigned i = 0; i < count; i++) + { + AtagConstantList[addr + i] = tag; + AddrKonst loc = { addr+i, tag }; + AddressConstantMap.Insert(ptrs[i], loc); + } + return addr; +} + +unsigned VMFunctionBuilder::AllocConstantsString(unsigned count, FString *ptrs) +{ + unsigned addr = StringConstantList.Reserve(count); + for (unsigned i = 0; i < count; i++) + { + StringConstantList[addr + i] = ptrs[i]; + StringConstantMap.Insert(ptrs[i], addr + i); + } + return addr; +} + + //========================================================================== // // VMFunctionBuilder :: ParamChange diff --git a/src/scripting/vm/vmbuilder.h b/src/scripting/vm/vmbuilder.h index d69c97707..5991d0711 100644 --- a/src/scripting/vm/vmbuilder.h +++ b/src/scripting/vm/vmbuilder.h @@ -42,10 +42,16 @@ public: void MakeFunction(VMScriptFunction *func); // Returns the constant register holding the value. - int GetConstantInt(int val); - int GetConstantFloat(double val); - int GetConstantAddress(void *ptr, VM_ATAG tag); - int GetConstantString(FString str); + unsigned GetConstantInt(int val); + unsigned GetConstantFloat(double val); + unsigned GetConstantAddress(void *ptr, VM_ATAG tag); + unsigned GetConstantString(FString str); + + unsigned AllocConstantsInt(unsigned int count, int *values); + unsigned AllocConstantsFloat(unsigned int count, double *values); + unsigned AllocConstantsAddress(unsigned int count, void **ptrs, VM_ATAG tag); + unsigned AllocConstantsString(unsigned int count, FString *ptrs); + // Returns the address of the next instruction to be emitted. size_t GetAddress(); @@ -82,19 +88,20 @@ public: private: struct AddrKonst { - int KonstNum; + unsigned KonstNum; VM_ATAG Tag; }; - // These map from the constant value to its position in the constant table. - TMap IntConstants; - TMap FloatConstants; - TMap AddressConstants; - TMap StringConstants; - int NumIntConstants; - int NumFloatConstants; - int NumAddressConstants; - int NumStringConstants; + TArray IntConstantList; + TArray FloatConstantList; + TArray AddressConstantList; + TArray AtagConstantList; + TArray StringConstantList; + // These map from the constant value to its position in the constant table. + TMap IntConstantMap; + TMap FloatConstantMap; + TMap AddressConstantMap; + TMap StringConstantMap; int MaxParam; int ActiveParam; diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index 031f3328b..c95699613 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -97,6 +97,9 @@ #define RIRIRI MODE_AI | MODE_BI | MODE_CI #define RIRII8 MODE_AI | MODE_BI | MODE_CIMMZ +#define RFRII8 MODE_AF | MODE_BI | MODE_CIMMZ +#define RPRII8 MODE_AP | MODE_BI | MODE_CIMMZ +#define RSRII8 MODE_AS | MODE_BI | MODE_CIMMZ #define RIRIKI MODE_AI | MODE_BI | MODE_CKI #define RIKIRI MODE_AI | MODE_BKI | MODE_CI #define RIKII8 MODE_AI | MODE_BKI | MODE_CIMMZ diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index e4ab95946..6202de3bb 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -84,6 +84,26 @@ begin: reg.a[a] = konsta[BC].v; reg.atag[a] = konstatag[BC]; NEXTOP; + + OP(LK_R) : + ASSERTD(a); ASSERTD(B); + reg.d[a] = konstd[reg.d[B] + C]; + NEXTOP; + OP(LKF_R) : + ASSERTF(a); ASSERTD(B); + reg.f[a] = konstf[reg.d[B] + C]; + NEXTOP; + OP(LKS_R) : + ASSERTS(a); ASSERTD(B); + reg.s[a] = konsts[reg.d[B] + C]; + NEXTOP; + OP(LKP_R) : + ASSERTA(a); ASSERTD(B); + b = reg.d[B] + C; + reg.a[a] = konsta[b].v; + reg.atag[a] = konstatag[b]; + NEXTOP; + OP(LFP): ASSERTA(a); assert(sfunc != NULL); assert(sfunc->ExtraSpace > 0); reg.a[a] = f->GetExtra(); diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 210ff9c49..6f78e9e4e 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -10,6 +10,10 @@ xx(LK, lk, LKI), // load integer constant xx(LKF, lk, LKF), // load float constant xx(LKS, lk, LKS), // load string constant xx(LKP, lk, LKP), // load pointer constant +xx(LK_R, lk, RIRII8), // load integer constant indexed +xx(LKF_R, lk, RFRII8), // load float constant indexed +xx(LKS_R, lk, RSRII8), // load string constant indexed +xx(LKP_R, lk, RPRII8), // load pointer constant indexed xx(LFP, lf, LFP), // load frame pointer // Load from memory. rA = *(rB + rkC) diff --git a/src/scripting/zscript/ast.cpp b/src/scripting/zscript/ast.cpp index d8945ca3b..3bdc2e244 100644 --- a/src/scripting/zscript/ast.cpp +++ b/src/scripting/zscript/ast.cpp @@ -595,6 +595,16 @@ static void PrintExprClassCast(FLispString &out, ZCC_TreeNode *node) out.Close(); } +static void PrintStaticArray(FLispString &out, ZCC_TreeNode *node) +{ + ZCC_StaticArrayStatement *enode = (ZCC_StaticArrayStatement *)node; + out.Open("static-array-stmt"); + PrintNodes(out, enode->Type, false); + out.AddName(enode->Id); + PrintNodes(out, enode->Values, false); + out.Close(); +} + static void PrintExprMemberAccess(FLispString &out, ZCC_TreeNode *node) { ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node; diff --git a/src/scripting/zscript/zcc-parse.lemon b/src/scripting/zscript/zcc-parse.lemon index 8bd9686e3..3380959ec 100644 --- a/src/scripting/zscript/zcc-parse.lemon +++ b/src/scripting/zscript/zcc-parse.lemon @@ -1559,6 +1559,29 @@ statement(X) ::= jump_statement(X). statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } statement(X) ::= local_var(A) SEMICOLON. { X = A; /*X-overwrites-A*/ } statement(X) ::= error SEMICOLON. { X = NULL; } +statement(X) ::= staticarray_statement(A). { X = A; /*X-overwrites-A*/ } + +/*----- Static array Statements -----*/ + +%type staticarray_statement{ZCC_StaticArrayStatement *} + +staticarray_statement(X) ::= STATIC CONST type(A) IDENTIFIER(B) LBRACKET RBRACKET EQ LBRACE expr_list(C) RBRACE. +{ + NEW_AST_NODE(StaticArrayStatement, stmt, A); + stmt->Type = A; + stmt->Id = ENamedName(B.Int); + stmt->Values = C; + X = stmt; +} + +staticarray_statement(X) ::= STATIC CONST type(A) LBRACKET RBRACKET IDENTIFIER(B) EQ LBRACE expr_list(C) RBRACE. +{ + NEW_AST_NODE(StaticArrayStatement, stmt, A); + stmt->Type = A; + stmt->Id = ENamedName(B.Int); + stmt->Values = C; + X = stmt; +} /*----- Jump Statements -----*/ diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index 7c78b3c1e..291387617 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -2826,6 +2826,15 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast) return new FxClassPtrCast(cls, ConvertNode(cc->Parameters)); } + case AST_StaticArrayStatement: + { + auto sas = static_cast(ast); + PType *ztype = DetermineType(ConvertClass, sas, sas->Id, sas->Type, false, false); + FArgumentList args; + ConvertNodeList(args, sas->Values); + // This has to let the code generator resolve the constants, not the Simplifier, which lacks all the necessary type info. + return new FxStaticArray(ztype, sas->Id, args, *ast); + } case AST_ExprMemberAccess: { diff --git a/src/scripting/zscript/zcc_parser.h b/src/scripting/zscript/zcc_parser.h index dd777eb6c..a19249208 100644 --- a/src/scripting/zscript/zcc_parser.h +++ b/src/scripting/zscript/zcc_parser.h @@ -103,6 +103,7 @@ enum EZCCTreeNodeType AST_VectorValue, AST_DeclFlags, AST_ClassCast, + AST_StaticArrayStatement, NUM_AST_NODE_TYPES }; @@ -406,6 +407,13 @@ struct ZCC_Statement : ZCC_TreeNode { }; +struct ZCC_StaticArrayStatement : ZCC_Statement +{ + ZCC_Type *Type; + ENamedName Id; + ZCC_Expression *Values; +}; + struct ZCC_CompoundStmt : ZCC_Statement { ZCC_Statement *Content;