Added post/pre increment/decrement operators to DECORATE

This commit is contained in:
Leonard2 2016-08-05 17:33:29 +02:00 committed by Christoph Oelckers
parent 2ef51d0d50
commit 8437313e7c
5 changed files with 306 additions and 66 deletions

View file

@ -18,6 +18,7 @@ typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
#define VARF_Method (1<<1) // func has an implied self parameter #define VARF_Method (1<<1) // func has an implied self parameter
#define VARF_Action (1<<2) // func has implied owner and state parameters #define VARF_Action (1<<2) // func has implied owner and state parameters
#define VARF_Native (1<<3) // func is native code/don't auto serialize field #define VARF_Native (1<<3) // func is native code/don't auto serialize field
#define VARF_ReadOnly (1<<4) // field is read only, do not write to it
// Symbol information ------------------------------------------------------- // Symbol information -------------------------------------------------------

View file

@ -631,38 +631,38 @@ void InitThingdef()
// Define some member variables we feel like exposing to the user // Define some member variables we feel like exposing to the user
PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols; PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols;
PType *array5 = NewArray(TypeSInt32, 5); PType *array5 = NewArray(TypeSInt32, 5);
symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor,Alpha))); symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor, Alpha)));
symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Yaw))); symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Yaw)));
symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor,args))); symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor, args)));
symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native, myoffsetof(AActor,ceilingz))); symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, ceilingz)));
symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native, myoffsetof(AActor,floorz))); symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, floorz)));
symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native, myoffsetof(AActor,health))); symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, health)));
symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor,Mass))); symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor, Mass)));
symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Pitch))); symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Pitch)));
symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Roll))); symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Roll)));
symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor,special))); symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor, special)));
symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native, myoffsetof(AActor,tid))); symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, tid)));
symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native, myoffsetof(AActor,TIDtoHate))); symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, TIDtoHate)));
symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native, myoffsetof(AActor,waterlevel))); symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, waterlevel)));
symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.X))); // must remain read-only! symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.X))); // must remain read-only!
symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Y))); // must remain read-only! symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Y))); // must remain read-only!
symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Z))); // must remain read-only! symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Z))); // must remain read-only!
symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native, myoffsetof(AActor,Vel.X))); symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X)));
symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y))); symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y)));
symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z))); symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z)));
symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.X))); symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X)));
symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y))); symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y)));
symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z))); symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z)));
symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X))); symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X)));
symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y))); symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y)));
symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor,Score))); symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor, Score)));
symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor,accuracy))); symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy)));
symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor,stamina))); symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor, stamina)));
symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native, myoffsetof(AActor,Height))); symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Height)));
symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native, myoffsetof(AActor,radius))); symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, radius)));
symt.AddSymbol(new PField(NAME_ReactionTime,TypeSInt32, VARF_Native, myoffsetof(AActor,reactiontime))); symt.AddSymbol(new PField(NAME_ReactionTime, TypeSInt32, VARF_Native, myoffsetof(AActor, reactiontime)));
symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor,meleerange))); symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor, meleerange)));
symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor,Speed))); symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor, Speed)));
symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native, myoffsetof(AActor,threshold))); symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold)));
symt.AddSymbol(new PField(NAME_DefThreshold,TypeSInt32, VARF_Native, myoffsetof(AActor,DefThreshold))); symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold)));
} }

View file

@ -63,6 +63,7 @@ static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls);
// //
// ParseExpression // ParseExpression
// [GRB] Parses an expression and stores it into Expression array // [GRB] Parses an expression and stores it into Expression array
// It's worth mentioning that this is using C++ operator precedence
// //
static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls); static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls);
@ -257,6 +258,10 @@ static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls)
case '+': case '+':
return new FxPlusSign(ParseExpressionA (sc, cls)); return new FxPlusSign(ParseExpressionA (sc, cls));
case TK_Incr:
case TK_Decr:
return new FxPreIncrDecr(ParseExpressionA(sc, cls), sc.TokenType);
default: default:
sc.UnGet(); sc.UnGet();
return ParseExpressionA (sc, cls); return ParseExpressionA (sc, cls);
@ -312,6 +317,14 @@ static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls)
sc.MustGetToken(']'); sc.MustGetToken(']');
base_expr = new FxArrayElement(base_expr, index); base_expr = new FxArrayElement(base_expr, index);
} }
else if (sc.CheckToken(TK_Incr))
{
return new FxPostIncrDecr(base_expr, TK_Incr);
}
else if (sc.CheckToken(TK_Decr))
{
return new FxPostIncrDecr(base_expr, TK_Decr);
}
else break; else break;
} }
@ -478,7 +491,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
} }
break; break;
} }
} }
else else
{ {
return new FxIdentifier(identifier, sc); return new FxIdentifier(identifier, sc);

View file

@ -201,7 +201,7 @@ public:
virtual FxExpression *Resolve(FCompileContext &ctx); virtual FxExpression *Resolve(FCompileContext &ctx);
virtual bool isConstant() const; virtual bool isConstant() const;
virtual void RequestAddress(); virtual bool RequestAddress();
virtual VMFunction *GetDirectFunction(); virtual VMFunction *GetDirectFunction();
bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); } bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); }
bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; } bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; }
@ -469,6 +469,45 @@ public:
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };
//==========================================================================
//
// FxPreIncrDecr
//
//==========================================================================
class FxPreIncrDecr : public FxExpression
{
int Token;
FxExpression *Base;
bool AddressRequested;
bool AddressWritable;
public:
FxPreIncrDecr(FxExpression *base, int token);
~FxPreIncrDecr();
FxExpression *Resolve(FCompileContext&);
bool RequestAddress();
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxPostIncrDecr
//
//==========================================================================
class FxPostIncrDecr : public FxExpression
{
int Token;
FxExpression *Base;
public:
FxPostIncrDecr(FxExpression *base, int token);
~FxPostIncrDecr();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//========================================================================== //==========================================================================
// //
// FxBinary // FxBinary
@ -753,7 +792,7 @@ public:
FxClassMember(FxExpression*, PField*, const FScriptPosition&); FxClassMember(FxExpression*, PField*, const FScriptPosition&);
~FxClassMember(); ~FxClassMember();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
void RequestAddress(); bool RequestAddress();
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };
@ -796,12 +835,13 @@ class FxArrayElement : public FxExpression
public: public:
FxExpression *Array; FxExpression *Array;
FxExpression *index; FxExpression *index;
//bool AddressRequested; bool AddressRequested;
bool AddressWritable;
FxArrayElement(FxExpression*, FxExpression*); FxArrayElement(FxExpression*, FxExpression*);
~FxArrayElement(); ~FxArrayElement();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
//void RequestAddress(); bool RequestAddress();
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);
}; };

View file

@ -218,13 +218,14 @@ FxExpression *FxExpression::Resolve(FCompileContext &ctx)
//========================================================================== //==========================================================================
// //
// // Returns true if we can write to the address.
// //
//========================================================================== //==========================================================================
void FxExpression::RequestAddress() bool FxExpression::RequestAddress()
{ {
ScriptPosition.Message(MSG_ERROR, "invalid dereference\n"); ScriptPosition.Message(MSG_ERROR, "invalid dereference\n");
return false;
} }
//========================================================================== //==========================================================================
@ -887,6 +888,166 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build)
return from; return from;
} }
//==========================================================================
//
// FxPreIncrDecr
//
//==========================================================================
FxPreIncrDecr::FxPreIncrDecr(FxExpression *base, int token)
: FxExpression(base->ScriptPosition), Base(base), Token(token)
{
AddressRequested = false;
AddressWritable = false;
}
FxPreIncrDecr::~FxPreIncrDecr()
{
SAFE_DELETE(Base);
}
bool FxPreIncrDecr::RequestAddress()
{
AddressRequested = true;
return AddressWritable;
}
FxExpression *FxPreIncrDecr::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(Base, ctx);
ValueType = Base->ValueType;
if (!Base->IsNumeric())
{
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this;
return nullptr;
}
else if (Base->ValueType == TypeBool)
{
ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars());
delete this;
return nullptr;
}
if (!(AddressWritable = Base->RequestAddress()))
{
ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value");
delete this;
return nullptr;
}
return this;
}
ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build)
{
assert(Token == TK_Incr || Token == TK_Decr);
assert(ValueType == Base->ValueType && IsNumeric());
int zero = build->GetConstantInt(0);
int regtype = ValueType->GetRegType();
ExpEmit pointer = Base->Emit(build);
ExpEmit value(build, regtype);
build->Emit(ValueType->GetLoadOp(), value.RegNum, pointer.RegNum, zero);
if (regtype == REGT_INT)
{
build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, value.RegNum, value.RegNum, build->GetConstantInt(1));
}
else
{
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 (AddressRequested)
{
value.Free(build);
return pointer;
}
pointer.Free(build);
return value;
}
//==========================================================================
//
// FxPostIncrDecr
//
//==========================================================================
FxPostIncrDecr::FxPostIncrDecr(FxExpression *base, int token)
: FxExpression(base->ScriptPosition), Base(base), Token(token)
{
}
FxPostIncrDecr::~FxPostIncrDecr()
{
SAFE_DELETE(Base);
}
FxExpression *FxPostIncrDecr::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(Base, ctx);
ValueType = Base->ValueType;
if (!Base->IsNumeric())
{
ScriptPosition.Message(MSG_ERROR, "Numeric type expected");
delete this;
return nullptr;
}
else if (Base->ValueType == TypeBool)
{
ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars());
delete this;
return nullptr;
}
if (!Base->RequestAddress())
{
ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value");
delete this;
return nullptr;
}
return this;
}
ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build)
{
assert(Token == TK_Incr || Token == TK_Decr);
assert(ValueType == Base->ValueType && IsNumeric());
int zero = build->GetConstantInt(0);
int regtype = ValueType->GetRegType();
ExpEmit pointer = Base->Emit(build);
ExpEmit out(build, regtype);
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero);
ExpEmit assign(build, regtype);
if (regtype == REGT_INT)
{
build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, assign.RegNum, out.RegNum, build->GetConstantInt(1));
}
else
{
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);
pointer.Free(build);
assign.Free(build);
return out;
}
//========================================================================== //==========================================================================
// //
// //
@ -2995,9 +3156,10 @@ FxClassMember::~FxClassMember()
// //
//========================================================================== //==========================================================================
void FxClassMember::RequestAddress() bool FxClassMember::RequestAddress()
{ {
AddressRequested = true; AddressRequested = true;
return !!(~membervar->Flags & VARF_ReadOnly);
} }
//========================================================================== //==========================================================================
@ -3027,6 +3189,17 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build)
ExpEmit obj = classx->Emit(build); ExpEmit obj = classx->Emit(build);
assert(obj.RegType == REGT_POINTER); assert(obj.RegType == REGT_POINTER);
if (obj.Konst)
{
// If the situation where we are dereferencing a constant
// pointer is common, then it would probably be worthwhile
// to add new opcodes for those. But as of right now, I
// don't expect it to be a particularly common case.
ExpEmit newobj(build, REGT_POINTER);
build->Emit(OP_LKP, newobj.RegNum, obj.RegNum);
obj = newobj;
}
if (AddressRequested) if (AddressRequested)
{ {
if (membervar->Offset == 0) if (membervar->Offset == 0)
@ -3040,20 +3213,8 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build)
} }
int offsetreg = build->GetConstantInt((int)membervar->Offset); int offsetreg = build->GetConstantInt((int)membervar->Offset);
ExpEmit loc, tmp; ExpEmit loc(build, membervar->Type->GetRegType());
if (obj.Konst)
{
// If the situation where we are dereferencing a constant
// pointer is common, then it would probably be worthwhile
// to add new opcodes for those. But as of right now, I
// don't expect it to be a particularly common case.
ExpEmit newobj(build, REGT_POINTER);
build->Emit(OP_LKP, newobj.RegNum, obj.RegNum);
obj = newobj;
}
loc = ExpEmit(build, membervar->Type->GetRegType());
build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg); build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg);
obj.Free(build); obj.Free(build);
return loc; return loc;
@ -3071,7 +3232,8 @@ FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index)
{ {
Array=base; Array=base;
index = _index; index = _index;
//AddressRequested = false; AddressRequested = false;
AddressWritable = false;
} }
//========================================================================== //==========================================================================
@ -3092,12 +3254,11 @@ FxArrayElement::~FxArrayElement()
// //
//========================================================================== //==========================================================================
/* bool FxArrayElement::RequestAddress()
void FxArrayElement::RequestAddress()
{ {
AddressRequested = true; AddressRequested = true;
return AddressWritable;
} }
*/
//========================================================================== //==========================================================================
// //
@ -3145,7 +3306,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
delete this; delete this;
return NULL; return NULL;
} }
Array->RequestAddress(); AddressWritable = Array->RequestAddress();
return this; return this;
} }
@ -3159,13 +3320,13 @@ 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);
PType *const elementtype = arraytype->ElementType; ExpEmit dest(build, arraytype->ElementType->GetRegType());
ExpEmit dest(build, elementtype->GetRegType());
if (start.Konst) if (start.Konst)
{ {
ExpEmit tmpstart(build, REGT_POINTER); ExpEmit tmpstart(build, REGT_POINTER);
build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum); build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum);
start.Free(build);
start = tmpstart; start = tmpstart;
} }
if (index->isConstant()) if (index->isConstant())
@ -3176,8 +3337,19 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
I_Error("Array index out of bounds"); I_Error("Array index out of bounds");
} }
indexval *= arraytype->ElementSize; indexval *= arraytype->ElementSize;
build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum,
start.RegNum, build->GetConstantInt(indexval)); if (AddressRequested)
{
if (indexval != 0)
{
build->Emit(OP_ADDA_RK, start.RegNum, start.RegNum, build->GetConstantInt(indexval));
}
}
else
{
build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum,
start.RegNum, build->GetConstantInt(indexval));
}
} }
else else
{ {
@ -3193,10 +3365,24 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
{ {
build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, shiftbits); 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 if (AddressRequested)
{
build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexv.RegNum);
}
else
{
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);
} }
if (AddressRequested)
{
dest.Free(build);
return start;
}
start.Free(build); start.Free(build);
return dest; return dest;
} }