mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 15:21:51 +00:00
- added static constant arrays. At the moment they can only be defined inside functions due to lack of dedicated storage inside classes for static data.
- added new VM instructions to access the constant tables with a variable index. - refactored VMFunctionBuilder's constant tables so that they are not limited to one entry per value. While this works fine for single values, it makes it impossible to store constant arrays in here.
This commit is contained in:
parent
bb25c5faaa
commit
5951a9449c
11 changed files with 413 additions and 106 deletions
|
@ -5402,7 +5402,13 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
|
||||||
FxLocalVariableDeclaration *local = ctx.FindLocalVariable(Identifier);
|
FxLocalVariableDeclaration *local = ctx.FindLocalVariable(Identifier);
|
||||||
if (local != nullptr)
|
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);
|
auto x = new FxLocalVariable(local, ScriptPosition);
|
||||||
delete this;
|
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<FxStaticArray*>(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);
|
ExpEmit start = Array->Emit(build);
|
||||||
PArray *const arraytype = static_cast<PArray*>(Array->ValueType);
|
PArray *const arraytype = static_cast<PArray*>(Array->ValueType);
|
||||||
|
|
||||||
|
/* what was this for?
|
||||||
if (start.Konst)
|
if (start.Konst)
|
||||||
{
|
{
|
||||||
ExpEmit tmpstart(build, REGT_POINTER);
|
ExpEmit tmpstart(build, REGT_POINTER);
|
||||||
|
@ -6364,16 +6403,17 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
||||||
start.Free(build);
|
start.Free(build);
|
||||||
start = tmpstart;
|
start = tmpstart;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if (index->isConstant())
|
if (index->isConstant())
|
||||||
{
|
{
|
||||||
unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt();
|
unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt();
|
||||||
assert(indexval < arraytype->ElementCount && "Array index out of bounds");
|
assert(indexval < arraytype->ElementCount && "Array index out of bounds");
|
||||||
indexval *= arraytype->ElementSize;
|
|
||||||
|
|
||||||
if (AddressRequested)
|
if (AddressRequested)
|
||||||
{
|
{
|
||||||
if (indexval != 0)
|
if (indexval != 0)
|
||||||
{
|
{
|
||||||
|
indexval *= arraytype->ElementSize;
|
||||||
if (!start.Fixed)
|
if (!start.Fixed)
|
||||||
{
|
{
|
||||||
build->Emit(OP_ADDA_RK, start.RegNum, start.RegNum, build->GetConstantInt(indexval));
|
build->Emit(OP_ADDA_RK, start.RegNum, start.RegNum, build->GetConstantInt(indexval));
|
||||||
|
@ -6389,61 +6429,90 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
||||||
}
|
}
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
else
|
else if (!start.Konst)
|
||||||
{
|
{
|
||||||
start.Free(build);
|
start.Free(build);
|
||||||
ExpEmit dest(build, ValueType->GetRegType());
|
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;
|
return dest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ExpEmit indexv(index->Emit(build));
|
ExpEmit indexv(index->Emit(build));
|
||||||
ExpEmit indexwork = indexv.Fixed ? ExpEmit(build, indexv.RegType) : indexv;
|
|
||||||
build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount);
|
build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount);
|
||||||
|
|
||||||
int shiftbits = 0;
|
if (!start.Konst)
|
||||||
while (1u << shiftbits < arraytype->ElementSize)
|
|
||||||
{
|
|
||||||
shiftbits++;
|
|
||||||
}
|
|
||||||
if (1u << shiftbits == arraytype->ElementSize)
|
|
||||||
{
|
{
|
||||||
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++;
|
||||||
}
|
}
|
||||||
}
|
if (1u << shiftbits == arraytype->ElementSize)
|
||||||
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);
|
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
|
else
|
||||||
{
|
{
|
||||||
start.Free(build);
|
start.Free(build);
|
||||||
// do not clobber local variables.
|
ExpEmit dest(build, ValueType->GetRegType());
|
||||||
ExpEmit temp(build, start.RegType);
|
// added 1 to use the *_R version that takes the offset from a register
|
||||||
build->Emit(OP_ADDA_RR, temp.RegNum, start.RegNum, indexwork.RegNum);
|
build->Emit(arraytype->ElementType->GetLoadOp() + 1, dest.RegNum, start.RegNum, indexwork.RegNum);
|
||||||
start = temp;
|
return dest;
|
||||||
}
|
}
|
||||||
return start;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
start.Free(build);
|
static int LKR_Ops[] = { OP_LK_R, OP_LKF_R, OP_LKS_R, OP_LKP_R };
|
||||||
ExpEmit dest(build, ValueType->GetRegType());
|
assert(start.RegType == ValueType->GetRegType());
|
||||||
// added 1 to use the *_R version that takes the offset from a register
|
ExpEmit dest(build, start.RegType);
|
||||||
build->Emit(arraytype->ElementType->GetLoadOp() + 1, dest.RegNum, start.RegNum, indexwork.RegNum);
|
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;
|
return dest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9241,3 +9310,82 @@ void FxLocalVariableDeclaration::Release(VMFunctionBuilder *build)
|
||||||
// Stack space will not be released because that would make controlled destruction impossible.
|
// 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.
|
// 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<int> cvalues;
|
||||||
|
for (auto v : values) cvalues.Push(static_cast<FxConstant *>(v)->GetValue().GetInt());
|
||||||
|
StackOffset = build->AllocConstantsInt(cvalues.Size(), &cvalues[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REGT_FLOAT:
|
||||||
|
{
|
||||||
|
TArray<double> cvalues;
|
||||||
|
for (auto v : values) cvalues.Push(static_cast<FxConstant *>(v)->GetValue().GetFloat());
|
||||||
|
StackOffset = build->AllocConstantsFloat(cvalues.Size(), &cvalues[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REGT_STRING:
|
||||||
|
{
|
||||||
|
TArray<FString> cvalues;
|
||||||
|
for (auto v : values) cvalues.Push(static_cast<FxConstant *>(v)->GetValue().GetString());
|
||||||
|
StackOffset = build->AllocConstantsString(cvalues.Size(), &cvalues[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REGT_POINTER:
|
||||||
|
{
|
||||||
|
TArray<void*> cvalues;
|
||||||
|
for (auto v : values) cvalues.Push(static_cast<FxConstant *>(v)->GetValue().GetPointer());
|
||||||
|
StackOffset = build->AllocConstantsAddress(cvalues.Size(), &cvalues[0], ElementType->GetLoadOp() == OP_LO ? ATAG_OBJECT : ATAG_GENERIC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ExpEmit();
|
||||||
|
}
|
||||||
|
|
|
@ -282,6 +282,8 @@ enum EFxType
|
||||||
EFX_Super,
|
EFX_Super,
|
||||||
EFX_StackVariable,
|
EFX_StackVariable,
|
||||||
EFX_MultiAssign,
|
EFX_MultiAssign,
|
||||||
|
EFX_StaticArray,
|
||||||
|
EFX_StaticArrayVariable,
|
||||||
EFX_COUNT
|
EFX_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1308,6 +1310,25 @@ public:
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
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
|
// FxSelf
|
||||||
|
@ -1529,6 +1550,7 @@ class FxCompoundStatement : public FxSequence
|
||||||
FxCompoundStatement *Outer = nullptr;
|
FxCompoundStatement *Outer = nullptr;
|
||||||
|
|
||||||
friend class FxLocalVariableDeclaration;
|
friend class FxLocalVariableDeclaration;
|
||||||
|
friend class FxStaticArray;
|
||||||
friend class FxMultiAssign;
|
friend class FxMultiAssign;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -1841,6 +1863,7 @@ class FxLocalVariableDeclaration : public FxExpression
|
||||||
{
|
{
|
||||||
friend class FxCompoundStatement;
|
friend class FxCompoundStatement;
|
||||||
friend class FxLocalVariable;
|
friend class FxLocalVariable;
|
||||||
|
friend class FxStaticArrayVariable;
|
||||||
|
|
||||||
FName Name;
|
FName Name;
|
||||||
FxExpression *Init;
|
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
|
#endif
|
||||||
|
|
|
@ -45,10 +45,6 @@
|
||||||
|
|
||||||
VMFunctionBuilder::VMFunctionBuilder(int numimplicits)
|
VMFunctionBuilder::VMFunctionBuilder(int numimplicits)
|
||||||
{
|
{
|
||||||
NumIntConstants = 0;
|
|
||||||
NumFloatConstants = 0;
|
|
||||||
NumAddressConstants = 0;
|
|
||||||
NumStringConstants = 0;
|
|
||||||
MaxParam = 0;
|
MaxParam = 0;
|
||||||
ActiveParam = 0;
|
ActiveParam = 0;
|
||||||
NumImplicits = numimplicits;
|
NumImplicits = numimplicits;
|
||||||
|
@ -74,25 +70,25 @@ VMFunctionBuilder::~VMFunctionBuilder()
|
||||||
|
|
||||||
void VMFunctionBuilder::MakeFunction(VMScriptFunction *func)
|
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.
|
// Copy code block.
|
||||||
memcpy(func->Code, &Code[0], Code.Size() * sizeof(VMOP));
|
memcpy(func->Code, &Code[0], Code.Size() * sizeof(VMOP));
|
||||||
|
|
||||||
// Create constant tables.
|
// Create constant tables.
|
||||||
if (NumIntConstants > 0)
|
if (IntConstantList.Size() > 0)
|
||||||
{
|
{
|
||||||
FillIntConstants(func->KonstD);
|
FillIntConstants(func->KonstD);
|
||||||
}
|
}
|
||||||
if (NumFloatConstants > 0)
|
if (FloatConstantList.Size() > 0)
|
||||||
{
|
{
|
||||||
FillFloatConstants(func->KonstF);
|
FillFloatConstants(func->KonstF);
|
||||||
}
|
}
|
||||||
if (NumAddressConstants > 0)
|
if (AddressConstantList.Size() > 0)
|
||||||
{
|
{
|
||||||
FillAddressConstants(func->KonstA, func->KonstATags());
|
FillAddressConstants(func->KonstA, func->KonstATags());
|
||||||
}
|
}
|
||||||
if (NumStringConstants > 0)
|
if (StringConstantList.Size() > 0)
|
||||||
{
|
{
|
||||||
FillStringConstants(func->KonstS);
|
FillStringConstants(func->KonstS);
|
||||||
}
|
}
|
||||||
|
@ -118,13 +114,7 @@ void VMFunctionBuilder::MakeFunction(VMScriptFunction *func)
|
||||||
|
|
||||||
void VMFunctionBuilder::FillIntConstants(int *konst)
|
void VMFunctionBuilder::FillIntConstants(int *konst)
|
||||||
{
|
{
|
||||||
TMapIterator<int, int> it(IntConstants);
|
memcpy(konst, &IntConstantList[0], sizeof(int) * IntConstantList.Size());
|
||||||
TMap<int, int>::Pair *pair;
|
|
||||||
|
|
||||||
while (it.NextPair(pair))
|
|
||||||
{
|
|
||||||
konst[pair->Value] = pair->Key;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -135,13 +125,7 @@ void VMFunctionBuilder::FillIntConstants(int *konst)
|
||||||
|
|
||||||
void VMFunctionBuilder::FillFloatConstants(double *konst)
|
void VMFunctionBuilder::FillFloatConstants(double *konst)
|
||||||
{
|
{
|
||||||
TMapIterator<double, int> it(FloatConstants);
|
memcpy(konst, &FloatConstantList[0], sizeof(double) * FloatConstantList.Size());
|
||||||
TMap<double, int>::Pair *pair;
|
|
||||||
|
|
||||||
while (it.NextPair(pair))
|
|
||||||
{
|
|
||||||
konst[pair->Value] = pair->Key;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -152,14 +136,8 @@ void VMFunctionBuilder::FillFloatConstants(double *konst)
|
||||||
|
|
||||||
void VMFunctionBuilder::FillAddressConstants(FVoidObj *konst, VM_ATAG *tags)
|
void VMFunctionBuilder::FillAddressConstants(FVoidObj *konst, VM_ATAG *tags)
|
||||||
{
|
{
|
||||||
TMapIterator<void *, AddrKonst> it(AddressConstants);
|
memcpy(konst, &AddressConstantList[0], sizeof(void*) * AddressConstantList.Size());
|
||||||
TMap<void *, AddrKonst>::Pair *pair;
|
memcpy(tags, &AtagConstantList[0], sizeof(VM_ATAG) * AtagConstantList.Size());
|
||||||
|
|
||||||
while (it.NextPair(pair))
|
|
||||||
{
|
|
||||||
konst[pair->Value.KonstNum].v = pair->Key;
|
|
||||||
tags[pair->Value.KonstNum] = pair->Value.Tag;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -170,12 +148,9 @@ void VMFunctionBuilder::FillAddressConstants(FVoidObj *konst, VM_ATAG *tags)
|
||||||
|
|
||||||
void VMFunctionBuilder::FillStringConstants(FString *konst)
|
void VMFunctionBuilder::FillStringConstants(FString *konst)
|
||||||
{
|
{
|
||||||
TMapIterator<FString, int> it(StringConstants);
|
for (auto &s : StringConstantList)
|
||||||
TMap<FString, int>::Pair *pair;
|
|
||||||
|
|
||||||
while (it.NextPair(pair))
|
|
||||||
{
|
{
|
||||||
konst[pair->Value] = pair->Key;
|
*konst++ = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,22 +158,21 @@ void VMFunctionBuilder::FillStringConstants(FString *konst)
|
||||||
//
|
//
|
||||||
// VMFunctionBuilder :: GetConstantInt
|
// VMFunctionBuilder :: GetConstantInt
|
||||||
//
|
//
|
||||||
// Returns a constant register initialized with the given value, or -1 if
|
// Returns a constant register initialized with the given value.
|
||||||
// there were no more constants free.
|
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
int VMFunctionBuilder::GetConstantInt(int val)
|
unsigned VMFunctionBuilder::GetConstantInt(int val)
|
||||||
{
|
{
|
||||||
int *locp = IntConstants.CheckKey(val);
|
unsigned int *locp = IntConstantMap.CheckKey(val);
|
||||||
if (locp != NULL)
|
if (locp != NULL)
|
||||||
{
|
{
|
||||||
return *locp;
|
return *locp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int loc = NumIntConstants++;
|
unsigned loc = IntConstantList.Push(val);
|
||||||
IntConstants.Insert(val, loc);
|
IntConstantMap.Insert(val, loc);
|
||||||
return loc;
|
return loc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,22 +181,21 @@ int VMFunctionBuilder::GetConstantInt(int val)
|
||||||
//
|
//
|
||||||
// VMFunctionBuilder :: GetConstantFloat
|
// VMFunctionBuilder :: GetConstantFloat
|
||||||
//
|
//
|
||||||
// Returns a constant register initialized with the given value, or -1 if
|
// Returns a constant register initialized with the given value.
|
||||||
// there were no more constants free.
|
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
int VMFunctionBuilder::GetConstantFloat(double val)
|
unsigned VMFunctionBuilder::GetConstantFloat(double val)
|
||||||
{
|
{
|
||||||
int *locp = FloatConstants.CheckKey(val);
|
unsigned *locp = FloatConstantMap.CheckKey(val);
|
||||||
if (locp != NULL)
|
if (locp != NULL)
|
||||||
{
|
{
|
||||||
return *locp;
|
return *locp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int loc = NumFloatConstants++;
|
unsigned loc = FloatConstantList.Push(val);
|
||||||
FloatConstants.Insert(val, loc);
|
FloatConstantMap.Insert(val, loc);
|
||||||
return loc;
|
return loc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,22 +204,21 @@ int VMFunctionBuilder::GetConstantFloat(double val)
|
||||||
//
|
//
|
||||||
// VMFunctionBuilder :: GetConstantString
|
// VMFunctionBuilder :: GetConstantString
|
||||||
//
|
//
|
||||||
// Returns a constant register initialized with the given value, or -1 if
|
// Returns a constant register initialized with the given value.
|
||||||
// there were no more constants free.
|
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
int VMFunctionBuilder::GetConstantString(FString val)
|
unsigned VMFunctionBuilder::GetConstantString(FString val)
|
||||||
{
|
{
|
||||||
int *locp = StringConstants.CheckKey(val);
|
unsigned *locp = StringConstantMap.CheckKey(val);
|
||||||
if (locp != NULL)
|
if (locp != NULL)
|
||||||
{
|
{
|
||||||
return *locp;
|
return *locp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int loc = NumStringConstants++;
|
int loc = StringConstantList.Push(val);
|
||||||
StringConstants.Insert(val, loc);
|
StringConstantMap.Insert(val, loc);
|
||||||
return 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)
|
if (ptr == NULL)
|
||||||
{ // Make all NULL pointers generic. (Or should we allow typed NULLs?)
|
{ // Make all NULL pointers generic. (Or should we allow typed NULLs?)
|
||||||
tag = ATAG_GENERIC;
|
tag = ATAG_GENERIC;
|
||||||
}
|
}
|
||||||
AddrKonst *locp = AddressConstants.CheckKey(ptr);
|
AddrKonst *locp = AddressConstantMap.CheckKey(ptr);
|
||||||
if (locp != NULL)
|
if (locp != NULL)
|
||||||
{
|
{
|
||||||
// There should only be one tag associated with a memory location.
|
// There should only be one tag associated with a memory location.
|
||||||
|
@ -275,12 +247,71 @@ int VMFunctionBuilder::GetConstantAddress(void *ptr, VM_ATAG tag)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddrKonst loc = { NumAddressConstants++, tag };
|
unsigned locc = AddressConstantList.Push(ptr);
|
||||||
AddressConstants.Insert(ptr, loc);
|
AtagConstantList.Push(tag);
|
||||||
|
|
||||||
|
AddrKonst loc = { locc, tag };
|
||||||
|
AddressConstantMap.Insert(ptr, loc);
|
||||||
return loc.KonstNum;
|
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
|
// VMFunctionBuilder :: ParamChange
|
||||||
|
|
|
@ -42,10 +42,16 @@ public:
|
||||||
void MakeFunction(VMScriptFunction *func);
|
void MakeFunction(VMScriptFunction *func);
|
||||||
|
|
||||||
// Returns the constant register holding the value.
|
// Returns the constant register holding the value.
|
||||||
int GetConstantInt(int val);
|
unsigned GetConstantInt(int val);
|
||||||
int GetConstantFloat(double val);
|
unsigned GetConstantFloat(double val);
|
||||||
int GetConstantAddress(void *ptr, VM_ATAG tag);
|
unsigned GetConstantAddress(void *ptr, VM_ATAG tag);
|
||||||
int GetConstantString(FString str);
|
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.
|
// Returns the address of the next instruction to be emitted.
|
||||||
size_t GetAddress();
|
size_t GetAddress();
|
||||||
|
@ -82,19 +88,20 @@ public:
|
||||||
private:
|
private:
|
||||||
struct AddrKonst
|
struct AddrKonst
|
||||||
{
|
{
|
||||||
int KonstNum;
|
unsigned KonstNum;
|
||||||
VM_ATAG Tag;
|
VM_ATAG Tag;
|
||||||
};
|
};
|
||||||
// These map from the constant value to its position in the constant table.
|
|
||||||
TMap<int, int> IntConstants;
|
|
||||||
TMap<double, int> FloatConstants;
|
|
||||||
TMap<void *, AddrKonst> AddressConstants;
|
|
||||||
TMap<FString, int> StringConstants;
|
|
||||||
|
|
||||||
int NumIntConstants;
|
TArray<int> IntConstantList;
|
||||||
int NumFloatConstants;
|
TArray<double> FloatConstantList;
|
||||||
int NumAddressConstants;
|
TArray<void *> AddressConstantList;
|
||||||
int NumStringConstants;
|
TArray<VM_ATAG> AtagConstantList;
|
||||||
|
TArray<FString> StringConstantList;
|
||||||
|
// These map from the constant value to its position in the constant table.
|
||||||
|
TMap<int, unsigned> IntConstantMap;
|
||||||
|
TMap<double, unsigned> FloatConstantMap;
|
||||||
|
TMap<void *, AddrKonst> AddressConstantMap;
|
||||||
|
TMap<FString, unsigned> StringConstantMap;
|
||||||
|
|
||||||
int MaxParam;
|
int MaxParam;
|
||||||
int ActiveParam;
|
int ActiveParam;
|
||||||
|
|
|
@ -97,6 +97,9 @@
|
||||||
|
|
||||||
#define RIRIRI MODE_AI | MODE_BI | MODE_CI
|
#define RIRIRI MODE_AI | MODE_BI | MODE_CI
|
||||||
#define RIRII8 MODE_AI | MODE_BI | MODE_CIMMZ
|
#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 RIRIKI MODE_AI | MODE_BI | MODE_CKI
|
||||||
#define RIKIRI MODE_AI | MODE_BKI | MODE_CI
|
#define RIKIRI MODE_AI | MODE_BKI | MODE_CI
|
||||||
#define RIKII8 MODE_AI | MODE_BKI | MODE_CIMMZ
|
#define RIKII8 MODE_AI | MODE_BKI | MODE_CIMMZ
|
||||||
|
|
|
@ -84,6 +84,26 @@ begin:
|
||||||
reg.a[a] = konsta[BC].v;
|
reg.a[a] = konsta[BC].v;
|
||||||
reg.atag[a] = konstatag[BC];
|
reg.atag[a] = konstatag[BC];
|
||||||
NEXTOP;
|
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):
|
OP(LFP):
|
||||||
ASSERTA(a); assert(sfunc != NULL); assert(sfunc->ExtraSpace > 0);
|
ASSERTA(a); assert(sfunc != NULL); assert(sfunc->ExtraSpace > 0);
|
||||||
reg.a[a] = f->GetExtra();
|
reg.a[a] = f->GetExtra();
|
||||||
|
|
|
@ -10,6 +10,10 @@ xx(LK, lk, LKI), // load integer constant
|
||||||
xx(LKF, lk, LKF), // load float constant
|
xx(LKF, lk, LKF), // load float constant
|
||||||
xx(LKS, lk, LKS), // load string constant
|
xx(LKS, lk, LKS), // load string constant
|
||||||
xx(LKP, lk, LKP), // load pointer 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
|
xx(LFP, lf, LFP), // load frame pointer
|
||||||
|
|
||||||
// Load from memory. rA = *(rB + rkC)
|
// Load from memory. rA = *(rB + rkC)
|
||||||
|
|
|
@ -595,6 +595,16 @@ static void PrintExprClassCast(FLispString &out, ZCC_TreeNode *node)
|
||||||
out.Close();
|
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)
|
static void PrintExprMemberAccess(FLispString &out, ZCC_TreeNode *node)
|
||||||
{
|
{
|
||||||
ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node;
|
ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node;
|
||||||
|
|
|
@ -1559,6 +1559,29 @@ statement(X) ::= jump_statement(X).
|
||||||
statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ }
|
statement(X) ::= assign_statement(A) SEMICOLON. { X = A; /*X-overwrites-A*/ }
|
||||||
statement(X) ::= local_var(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) ::= 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 -----*/
|
/*----- Jump Statements -----*/
|
||||||
|
|
||||||
|
|
|
@ -2826,6 +2826,15 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
||||||
return new FxClassPtrCast(cls, ConvertNode(cc->Parameters));
|
return new FxClassPtrCast(cls, ConvertNode(cc->Parameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case AST_StaticArrayStatement:
|
||||||
|
{
|
||||||
|
auto sas = static_cast<ZCC_StaticArrayStatement *>(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:
|
case AST_ExprMemberAccess:
|
||||||
{
|
{
|
||||||
|
|
|
@ -103,6 +103,7 @@ enum EZCCTreeNodeType
|
||||||
AST_VectorValue,
|
AST_VectorValue,
|
||||||
AST_DeclFlags,
|
AST_DeclFlags,
|
||||||
AST_ClassCast,
|
AST_ClassCast,
|
||||||
|
AST_StaticArrayStatement,
|
||||||
|
|
||||||
NUM_AST_NODE_TYPES
|
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
|
struct ZCC_CompoundStmt : ZCC_Statement
|
||||||
{
|
{
|
||||||
ZCC_Statement *Content;
|
ZCC_Statement *Content;
|
||||||
|
|
Loading…
Reference in a new issue