rewrite array codegen for field access

fixes major codegen bug
This commit is contained in:
Ricardo Luís Vaz Silva 2025-06-22 02:27:07 -03:00
commit 99ffd8727b

View file

@ -8072,7 +8072,6 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
{
arraytype = static_cast<PArray*>(Array->ValueType);
}
ExpEmit arrayvar = Array->Emit(build);
ExpEmit start;
ExpEmit bound;
bool nestedarray = false;
@ -8080,31 +8079,99 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
if (SizeAddr != ~0u)
{
bool ismeta = Array->ExprType == EFX_ClassMember && static_cast<FxClassMember*>(Array)->membervar->Flags & VARF_Meta;
start = ExpEmit(build, REGT_POINTER);
build->Emit(OP_LP, start.RegNum, arrayvar.RegNum, build->GetConstantInt(0));
auto f = Create<PField>(NAME_None, TypeUInt32, ismeta? VARF_Meta : 0, SizeAddr);
auto arraymemberbase = static_cast<FxMemberBase *>(Array);
auto origmembervar = arraymemberbase->membervar;
auto origaddrreq = arraymemberbase->AddressRequested;
auto origvaluetype = Array->ValueType;
if (Array->ExprType == EFX_StructMember || Array->ExprType == EFX_ClassMember)
{
struct DummyVar : public FxExpression
{
ExpEmit dummy;
DummyVar(ExpEmit e) : FxExpression(EFX_Expression,{}), dummy(e){}
ExpEmit Emit(VMFunctionBuilder *build)
{
return dummy;
};
};
arraymemberbase->membervar = f;
arraymemberbase->AddressRequested = false;
Array->ValueType = TypeUInt32;
//fix expression bug
FxStructMember * orig = static_cast<FxStructMember *>(Array);
FxExpression * prev = orig->classx;
ExpEmit objvar = prev->Emit(build);
bool wasFixed = objvar.Fixed;
bound = Array->Emit(build);
objvar.Fixed = true;
arraymemberbase->membervar = origmembervar;
arraymemberbase->AddressRequested = origaddrreq;
Array->ValueType = origvaluetype;
orig->classx = new DummyVar(objvar);
orig->classx->ValueType = prev->ValueType;
ExpEmit arrayvar = Array->Emit(build);
start = ExpEmit(build, REGT_POINTER);
delete orig->classx;
orig->classx = prev;
arrayvar.Free(build);
build->Emit(OP_LP, start.RegNum, arrayvar.RegNum, build->GetConstantInt(0));
if(ismeta)
{
// [Jay0]
// ugh do it the old way for meta since i don't want to duplicate that code here, but this time it only double-emits the member access, not the function call, so no bad side-effects, still not "right" though
// TODO handle meta better
auto origmembervar = arraymemberbase->membervar;
auto origaddrreq = arraymemberbase->AddressRequested;
auto origvaluetype = Array->ValueType;
arraymemberbase->membervar = f;
arraymemberbase->AddressRequested = false;
Array->ValueType = TypeUInt32;
bound = Array->Emit(build);
arraymemberbase->membervar = origmembervar;
arraymemberbase->AddressRequested = origaddrreq;
Array->ValueType = origvaluetype;
}
else
{
bound = ExpEmit(build, REGT_INT);
build->Emit(OP_LW, bound.RegNum, objvar.RegNum, build->GetConstantInt((int)SizeAddr));
}
objvar.Fixed = wasFixed;
objvar.Free(build);
arrayvar.Free(build);
}
else
{
// [Jay0]
// now only runs for global variables and stack variables, so the double-emit is """fine"""
// TODO replace this entirely with something better still
ExpEmit arrayvar = Array->Emit(build);
start = ExpEmit(build, REGT_POINTER);
build->Emit(OP_LP, start.RegNum, arrayvar.RegNum, build->GetConstantInt(0));
auto origmembervar = arraymemberbase->membervar;
auto origaddrreq = arraymemberbase->AddressRequested;
auto origvaluetype = Array->ValueType;
arraymemberbase->membervar = f;
arraymemberbase->AddressRequested = false;
Array->ValueType = TypeUInt32;
bound = Array->Emit(build);
arraymemberbase->membervar = origmembervar;
arraymemberbase->AddressRequested = origaddrreq;
Array->ValueType = origvaluetype;
arrayvar.Free(build);
}
}
else if ((Array->ExprType == EFX_ArrayElement || Array->ExprType == EFX_OutVarDereference) && Array->isStaticArray())
{
ExpEmit arrayvar = Array->Emit(build);
bound = ExpEmit(build, REGT_INT);
build->Emit(OP_LW, bound.RegNum, arrayvar.RegNum, build->GetConstantInt(myoffsetof(FArray, Count)));
@ -8114,7 +8181,10 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
nestedarray = true;
}
else start = arrayvar;
else
{
start = Array->Emit(build);
}
if (index->isConstant())
{