- process most of the remaining statement types.

- extend assignment operations to handle local variables (untested.)
- make the implicit function arguments read only.
This commit is contained in:
Christoph Oelckers 2016-10-21 01:12:54 +02:00
parent 24394dfc92
commit 9f99ca4788
8 changed files with 277 additions and 42 deletions

View file

@ -500,6 +500,18 @@ int PType::GetLoadOp() const
return OP_NOP;
}
//==========================================================================
//
// PType :: GetMoveOp
//
//==========================================================================
int PType::GetMoveOp() const
{
assert(0 && "Cannot move this type");
return OP_NOP;
}
//==========================================================================
//
// PType :: GetRegType
@ -974,6 +986,17 @@ int PInt::GetLoadOp() const
}
}
//==========================================================================
//
// PInt :: GetLoadOp
//
//==========================================================================
int PInt::GetMoveOp() const
{
return OP_MOVE;
}
//==========================================================================
//
// PInt :: GetRegType
@ -1271,6 +1294,17 @@ int PFloat::GetLoadOp() const
return OP_NOP;
}
//==========================================================================
//
// PFloat :: GetMoveOp
//
//==========================================================================
int PFloat::GetMoveOp() const
{
return OP_MOVEF;
}
//==========================================================================
//
// PFloat :: GetRegType
@ -1540,6 +1574,17 @@ int PStatePointer::GetLoadOp() const
return OP_LP;
}
//==========================================================================
//
// PStatePointer :: GetMoveOp
//
//==========================================================================
int PStatePointer::GetMoveOp() const
{
return OP_MOVEA;
}
//==========================================================================
//
// PStatePointer :: GetRegType
@ -1627,6 +1672,17 @@ int PPointer::GetLoadOp() const
return PointedType->IsKindOf(RUNTIME_CLASS(PClass)) ? OP_LO : OP_LP;
}
//==========================================================================
//
// PPointer :: GetMoveOp
//
//==========================================================================
int PPointer::GetMoveOp() const
{
return OP_MOVEA;
}
//==========================================================================
//
// PPointer :: GetRegType

View file

@ -28,7 +28,7 @@ enum
VARF_Final = (1<<9), // Function may not be overridden in subclasses
VARF_In = (1<<10),
VARF_Out = (1<<11),
VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare when checking function signatures)
VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures)
VARF_Static = (1<<13), // static class data (by necessity read only.)
};
@ -272,6 +272,9 @@ public:
// Gets the opcode to load from memory to a register
virtual int GetLoadOp() const;
// Gets the opcode to move from register to another register
virtual int GetMoveOp() const;
// Gets the register type for this type
virtual int GetRegType() const;
@ -409,6 +412,7 @@ public:
virtual double GetValueFloat(void *addr) const;
virtual int GetStoreOp() const;
virtual int GetLoadOp() const;
virtual int GetMoveOp() const;
virtual int GetRegType() const;
bool Unsigned;
@ -438,6 +442,7 @@ public:
virtual double GetValueFloat(void *addr) const;
virtual int GetStoreOp() const;
virtual int GetLoadOp() const;
virtual int GetMoveOp() const;
virtual int GetRegType() const;
protected:
PFloat();
@ -516,6 +521,7 @@ public:
virtual int GetStoreOp() const;
virtual int GetLoadOp() const;
virtual int GetMoveOp() const;
virtual int GetRegType() const;
};
@ -530,6 +536,7 @@ public:
virtual int GetStoreOp() const;
virtual int GetLoadOp() const;
virtual int GetMoveOp() const;
virtual int GetRegType() const;
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;

View file

@ -160,6 +160,18 @@ void FCompileContext::CheckReturn(PPrototype *proto, FScriptPosition &pos)
}
}
FxLocalVariableDeclaration *FCompileContext::FindLocalVariable(FName name)
{
if (Block == nullptr)
{
return nullptr;
}
else
{
return Block->FindLocalVariable(name, *this);
}
}
//==========================================================================
//
// ExpEmit
@ -1611,9 +1623,13 @@ ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build)
int zero = build->GetConstantInt(0);
int regtype = ValueType->GetRegType();
ExpEmit pointer = Base->Emit(build);
ExpEmit value = pointer;
ExpEmit value(build, regtype);
build->Emit(ValueType->GetLoadOp(), value.RegNum, pointer.RegNum, zero);
if (!pointer.Target)
{
value = ExpEmit(build, regtype);
build->Emit(ValueType->GetLoadOp(), value.RegNum, pointer.RegNum, zero);
}
if (regtype == REGT_INT)
{
@ -1624,7 +1640,10 @@ ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build)
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 (!pointer.Target)
{
build->Emit(ValueType->GetStoreOp(), pointer.RegNum, value.RegNum, zero);
}
if (AddressRequested)
{
@ -1690,9 +1709,13 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build)
int zero = build->GetConstantInt(0);
int regtype = ValueType->GetRegType();
ExpEmit pointer = Base->Emit(build);
ExpEmit out = pointer;
ExpEmit out(build, regtype);
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero);
if (!pointer.Target)
{
out = ExpEmit(build, regtype);
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero);
}
ExpEmit assign(build, regtype);
if (regtype == REGT_INT)
@ -1704,7 +1727,10 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build)
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);
if (!pointer.Target)
{
build->Emit(ValueType->GetStoreOp(), pointer.RegNum, assign.RegNum, zero);
}
pointer.Free(build);
assign.Free(build);
@ -1781,6 +1807,7 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
ExpEmit FxAssign::Emit(VMFunctionBuilder *build)
{
static const BYTE loadops[] = { OP_NOP, OP_LK, OP_LKF, OP_LKS, OP_LKP };
assert(ValueType == Base->ValueType && IsNumeric());
assert(ValueType->GetRegType() == Right->ValueType->GetRegType());
@ -1788,16 +1815,31 @@ ExpEmit FxAssign::Emit(VMFunctionBuilder *build)
Address = pointer;
ExpEmit result = Right->Emit(build);
if (result.Konst)
{
ExpEmit temp(build, result.RegType);
build->Emit(result.RegType == REGT_FLOAT ? OP_LKF : OP_LK, temp.RegNum, result.RegNum);
result.Free(build);
result = temp;
}
assert(result.RegType <= REGT_TYPE);
build->Emit(ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0));
if (pointer.Target)
{
if (result.Konst)
{
build->Emit(loadops[result.RegType], pointer.RegNum, result.RegNum);
}
else
{
build->Emit(Right->ValueType->GetMoveOp(), pointer.RegNum, result.RegNum);
}
}
else
{
if (result.Konst)
{
ExpEmit temp(build, result.RegType);
build->Emit(loadops[result.RegType], temp.RegNum, result.RegNum);
result.Free(build);
result = temp;
}
build->Emit(ValueType->GetStoreOp(), pointer.RegNum, result.RegNum, build->GetConstantInt(0));
}
if (AddressRequested)
{
@ -1837,9 +1879,16 @@ ExpEmit FxAssignSelf::Emit(VMFunctionBuilder *build)
{
assert(ValueType = Assignment->ValueType);
ExpEmit pointer = Assignment->Address; // FxAssign should have already emitted it
ExpEmit out(build, ValueType->GetRegType());
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0));
return out;
if (!pointer.Target)
{
ExpEmit out(build, ValueType->GetRegType());
build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, build->GetConstantInt(0));
return out;
}
else
{
return pointer;
}
}
//==========================================================================
@ -3858,8 +3907,15 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
CHECKRESOLVED();
// Local variables have highest priority.
FxLocalVariableDeclaration *local = ctx.FindLocalVariable(Identifier);
if (local != nullptr)
{
auto x = new FxLocalVariable(local, ScriptPosition);
delete this;
return x->Resolve(ctx);
}
// Ugh, the horror. Constants need to be taken from the owning class, but members from the self class to catch invalid accesses here...
// see if the current class (if valid) defines something with this name.
PSymbolTable *symtbl;
if ((sym = ctx.FindInClass(Identifier, symtbl)) != nullptr)
@ -3959,6 +4015,40 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
}
//==========================================================================
//
//
//
//==========================================================================
FxLocalVariable::FxLocalVariable(FxLocalVariableDeclaration *var, const FScriptPosition &sc)
: FxExpression(sc)
{
Variable = var;
AddressRequested = false;
}
FxExpression *FxLocalVariable::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
return this;
}
bool FxLocalVariable::RequestAddress(bool *writable)
{
AddressRequested = true;
if (writable != nullptr) *writable = !(Variable->VarFlags & VARF_ReadOnly);
return true;
}
ExpEmit FxLocalVariable::Emit(VMFunctionBuilder *build)
{
ExpEmit ret(Variable->RegNum, Variable->ValueType->GetRegType(), false, true);
if (AddressRequested) ret.Target = true;
return ret;
}
//==========================================================================
//
//
@ -3998,9 +4088,7 @@ FxExpression *FxSelf::Resolve(FCompileContext& ctx)
ExpEmit FxSelf::Emit(VMFunctionBuilder *build)
{
// self is always the first pointer passed to the function
ExpEmit me(0, REGT_POINTER);
me.Fixed = true;
return me;
return ExpEmit(0, REGT_POINTER, false, true);
}
@ -6238,10 +6326,11 @@ ExpEmit FxDamageValue::Emit(VMFunctionBuilder *build)
//
//==========================================================================
FxLocalVariableDeclaration::FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, const FScriptPosition &p)
FxLocalVariableDeclaration::FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p)
:FxExpression(p)
{
ValueType = type;
VarFlags = varflags;
Name = name;
Init = initval == nullptr? nullptr : new FxTypeCast(initval, type, false);
}

View file

@ -85,6 +85,7 @@ struct FCompileContext
void HandleJumps(int token, FxExpression *handler);
void CheckReturn(PPrototype *proto, FScriptPosition &pos);
FxLocalVariableDeclaration *FindLocalVariable(FName name);
};
//==========================================================================
@ -198,7 +199,7 @@ struct ExpEmit
void Free(VMFunctionBuilder *build);
void Reuse(VMFunctionBuilder *build);
BYTE RegNum, RegType, Konst:1, Fixed:1, Final:1;
BYTE RegNum, RegType, Konst:1, Fixed:1, Final:1, Target:1;
};
//==========================================================================
@ -964,6 +965,24 @@ public:
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxLocalVariable
//
//==========================================================================
class FxLocalVariable : public FxExpression
{
public:
FxLocalVariableDeclaration *Variable;
bool AddressRequested;
FxLocalVariable(FxLocalVariableDeclaration*, const FScriptPosition&);
FxExpression *Resolve(FCompileContext&);
bool RequestAddress(bool *writable);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxSelf
@ -1382,13 +1401,15 @@ public:
class FxLocalVariableDeclaration : public FxExpression
{
friend class FxCompoundStatement;
friend class FxLocalVariable;
FName Name;
FxExpression *Init;
int VarFlags;
public:
int RegNum = -1;
FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, const FScriptPosition &p);
FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p);
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
void Release(VMFunctionBuilder *build);

View file

@ -90,7 +90,7 @@ void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, TArray<FNam
{
// implied self pointer
if (args != nullptr) args->Push(NewPointer(cls));
if (argflags != nullptr) argflags->Push(VARF_Implicit);
if (argflags != nullptr) argflags->Push(VARF_Implicit | VARF_ReadOnly);
if (argnames != nullptr) argnames->Push(NAME_self);
}
if (funcflags & VARF_Action)
@ -111,8 +111,8 @@ void SetImplicitArgs(TArray<PType *> *args, TArray<DWORD> *argflags, TArray<FNam
}
if (argflags != nullptr)
{
argflags->Push(VARF_Implicit);
argflags->Push(VARF_Implicit);
argflags->Push(VARF_Implicit | VARF_ReadOnly);
argflags->Push(VARF_Implicit | VARF_ReadOnly);
}
if (argnames != nullptr)
{

View file

@ -693,8 +693,9 @@ void FFunctionBuildList::Build()
{
auto type = item.Func->Variants[0].Proto->ArgumentTypes[i];
auto name = item.Func->Variants[0].ArgNames[i];
// this won't get resolved and won't get emitted. This is only needed so that the code generator can retrieve the necessary info to do its work.
auto local = new FxLocalVariableDeclaration(type, name, nullptr, FScriptPosition());
auto flags = item.Func->Variants[0].ArgFlags[i];
// this won't get resolved and won't get emitted. It is only needed so that the code generator can retrieve the necessary info about this argument to do its work.
auto local = new FxLocalVariableDeclaration(type, name, nullptr, flags, FScriptPosition());
local->RegNum = buildit.Registers[type->GetRegType()].Get(1);
ctx.FunctionArgs.Push(local);
}

View file

@ -194,7 +194,7 @@ begin:
ASSERTF(a+2); ASSERTA(B); ASSERTKD(C);
GETADDR(PB,KC,X_READ_NIL);
{
float *v = (float *)ptr;
auto v = (double *)ptr;
reg.f[a] = v[0];
reg.f[a+1] = v[1];
reg.f[a+2] = v[2];
@ -204,7 +204,7 @@ begin:
ASSERTF(a+2); ASSERTA(B); ASSERTD(C);
GETADDR(PB,RC,X_READ_NIL);
{
float *v = (float *)ptr;
auto v = (double *)ptr;
reg.f[a] = v[0];
reg.f[a+1] = v[1];
reg.f[a+2] = v[2];
@ -290,20 +290,20 @@ begin:
ASSERTA(a); ASSERTF(B+2); ASSERTKD(C);
GETADDR(PA,KC,X_WRITE_NIL);
{
float *v = (float *)ptr;
v[0] = (float)reg.f[B];
v[1] = (float)reg.f[B+1];
v[2] = (float)reg.f[B+2];
auto v = (double *)ptr;
v[0] = reg.f[B];
v[1] = reg.f[B+1];
v[2] = reg.f[B+2];
}
NEXTOP;
OP(SV_R):
ASSERTA(a); ASSERTF(B+2); ASSERTD(C);
GETADDR(PA,RC,X_WRITE_NIL);
{
float *v = (float *)ptr;
v[0] = (float)reg.f[B];
v[1] = (float)reg.f[B+1];
v[2] = (float)reg.f[B+2];
auto v = (double *)ptr;
v[0] = reg.f[B];
v[1] = reg.f[B+1];
v[2] = reg.f[B+2];
}
NEXTOP;
OP(SBIT):

View file

@ -42,6 +42,7 @@
#include "cmdlib.h"
#include "m_alloc.h"
#include "zcc_parser.h"
#include "zcc-parse.h"
#include "zcc_compile.h"
#include "v_text.h"
#include "p_lnspec.h"
@ -2344,11 +2345,42 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
// The function name is a simple identifier.
return new FxFunctionCall(static_cast<ZCC_ExprID *>(fcall->Function)->Identifier, NAME_None, ConvertNodeList(fcall->Parameters), *ast);
// not yet done
case AST_ExprTypeRef:
case AST_SwitchStmt:
case AST_CaseStmt:
case AST_ExprMemberAccess:
// calling a class member through its pointer
// todo.
break;
case AST_AssignStmt:
{
auto assign = static_cast<ZCC_AssignStmt *>(ast);
switch (assign->AssignOp)
{
case ZCC_EQ:
// this ignores multi-assign statements (these should probably be disabled in the grammar.)
return new FxAssign(ConvertNode(assign->Dests), ConvertNode(assign->Sources));
case ZCC_MULEQ:
case ZCC_DIVEQ:
case ZCC_MODEQ:
case ZCC_ADDEQ:
case ZCC_SUBEQ:
case ZCC_LSHEQ:
case ZCC_RSHEQ:
case ZCC_ANDEQ:
case ZCC_OREQ:
case ZCC_XOREQ:
//break;
default:
Error(ast, "Invalid assign statement");
}
break;
}
case AST_ExprBinary:
// Array syntax for randoms. They are internally stored as ExprBinary with both an identifier on the left and right side.
if (fcall->Function->Operation == PEX_ArrayAccess)
@ -2546,7 +2578,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
{
val = node->Init ? ConvertNode(node->Init) : nullptr;
}
list->Add(new FxLocalVariableDeclaration(type, node->Name, val, *node));
list->Add(new FxLocalVariableDeclaration(type, node->Name, val, 0, *node)); // todo: Handle flags in the grammar.
}
node = static_cast<decltype(node)>(node->SiblingNext);
@ -2576,6 +2608,35 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
}
}
case AST_BreakStmt:
case AST_ContinueStmt:
return new FxJumpStatement(ast->NodeType == AST_BreakStmt ? TK_Break : TK_Continue, *ast);
case AST_IfStmt:
{
auto iff = static_cast<ZCC_IfStmt *>(ast);
return new FxIfStatement(ConvertNode(iff->Condition), ConvertNode(iff->TruePath), ConvertNode(iff->FalsePath), *ast);
}
case AST_IterationStmt:
{
auto iter = static_cast<ZCC_IterationStmt *>(ast);
if (iter->CheckAt == ZCC_IterationStmt::End)
{
assert(iter->LoopBumper == nullptr);
return new FxDoWhileLoop(ConvertNode(iter->LoopCondition), ConvertNode(iter->LoopStatement), *ast);
}
else if (iter->LoopBumper != nullptr)
{
return new FxForLoop(nullptr, ConvertNode(iter->LoopCondition), ConvertNode(iter->LoopBumper), ConvertNode(iter->LoopStatement), *ast);
}
else
{
return new FxWhileLoop(ConvertNode(iter->LoopCondition), ConvertNode(iter->LoopStatement), *ast);
}
}
case AST_CompoundStmt:
{
auto x = new FxCompoundStatement(*ast);