Generalize FxArrayElement to work with all numeric elements (not just 32-bit ints)

This commit is contained in:
Randy Heit 2016-04-03 16:07:51 -05:00
parent 0cc2705b99
commit 3357af32e5
2 changed files with 23 additions and 10 deletions

View file

@ -2994,10 +2994,10 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
} }
ValueType = arraytype->ElementType; ValueType = arraytype->ElementType;
if (ValueType->GetRegType() != REGT_INT) if (ValueType->GetRegType() != REGT_INT && ValueType->GetRegType() != REGT_FLOAT)
{ {
// int arrays only for now // int arrays only for now
ScriptPosition.Message(MSG_ERROR, "Only integer arrays are supported."); ScriptPosition.Message(MSG_ERROR, "Only numeric arrays are supported.");
delete this; delete this;
return NULL; return NULL;
} }
@ -3014,7 +3014,10 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
{ {
ExpEmit start = Array->Emit(build); ExpEmit start = Array->Emit(build);
ExpEmit dest(build, REGT_INT); PArray *const arraytype = static_cast<PArray*>(Array->ValueType);
PType *const elementtype = arraytype->ElementType;
ExpEmit dest(build, elementtype->GetRegType());
if (start.Konst) if (start.Konst)
{ {
ExpEmit tmpstart(build, REGT_POINTER); ExpEmit tmpstart(build, REGT_POINTER);
@ -3024,19 +3027,30 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
if (index->isConstant()) if (index->isConstant())
{ {
unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt(); unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt();
if (indexval >= static_cast<PArray*>(Array->ValueType)->ElementCount) if (indexval >= arraytype->ElementCount)
{ {
I_Error("Array index out of bounds"); I_Error("Array index out of bounds");
} }
indexval <<= 2; indexval *= arraytype->ElementSize;
build->Emit(OP_LW, dest.RegNum, start.RegNum, build->GetConstantInt(indexval)); build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum,
start.RegNum, build->GetConstantInt(indexval));
} }
else else
{ {
ExpEmit indexv(index->Emit(build)); ExpEmit indexv(index->Emit(build));
build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, 2); int shiftbits = 0;
build->Emit(OP_BOUND, indexv.RegNum, static_cast<PArray*>(Array->ValueType)->ElementCount); while (1 << shiftbits < arraytype->ElementSize)
build->Emit(OP_LW_R, dest.RegNum, start.RegNum, indexv.RegNum); {
shiftbits++;
}
assert(1 << shiftbits == arraytype->ElementSize && "Element sizes other than power of 2 are not implemented");
build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount);
if (shiftbits > 0)
{
build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, shiftbits);
}
build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that
dest.RegNum, start.RegNum, indexv.RegNum); // takes the offset from a register
indexv.Free(build); indexv.Free(build);
} }
start.Free(build); start.Free(build);

View file

@ -588,7 +588,6 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl
sym->Offset = cls->Extend(type); sym->Offset = cls->Extend(type);
if (symt->AddSymbol(sym) == NULL) if (symt->AddSymbol(sym) == NULL)
{ {
delete sym;
sc.ScriptMessage ("'%s' is already defined in '%s'.", sc.ScriptMessage ("'%s' is already defined in '%s'.",
symname.GetChars(), cls ? cls->TypeName.GetChars() : "Global"); symname.GetChars(), cls ? cls->TypeName.GetChars() : "Global");
FScriptPosition::ErrorCounter++; FScriptPosition::ErrorCounter++;