From 2984d44754e6c07eff9afb5edd4624f45bc76e57 Mon Sep 17 00:00:00 2001 From: Ethan MacDonald Date: Sat, 23 Aug 2025 16:14:47 -0300 Subject: [PATCH 1/9] Adding IR emitter --- FxScript.cpp | 2055 ++++++++++++++++++++++++++++-------------- FxScript.hpp | 215 ++++- FxScriptBytecode.hpp | 88 +- 3 files changed, 1626 insertions(+), 732 deletions(-) diff --git a/FxScript.cpp b/FxScript.cpp index 62cebcf..2a3e7a0 100644 --- a/FxScript.cpp +++ b/FxScript.cpp @@ -1,9 +1,10 @@ #include "FxScript.hpp" +#include "FxScriptUtil.hpp" + #include -#include -#include "FxScriptUtil.hpp" +#include #define FX_SCRIPT_SCOPE_GLOBAL_VARS_START_SIZE 32 #define FX_SCRIPT_SCOPE_LOCAL_VARS_START_SIZE 16 @@ -14,7 +15,7 @@ using Token = FxTokenizer::Token; using TT = FxTokenizer::TokenType; -FxScriptValue FxScriptValue::None{}; +FxScriptValue FxScriptValue::None {}; void FxConfigScript::LoadFile(const char* path) { @@ -69,7 +70,8 @@ Token& FxConfigScript::EatToken(TT token_type) { Token& token = GetToken(); if (token.Type != token_type) { - printf("[ERROR] %u:%u: Unexpected token type %s when expecting %s!\n", token.FileLine, token.FileColumn, FxTokenizer::GetTypeName(token.Type), FxTokenizer::GetTypeName(token_type)); + printf("[ERROR] %u:%u: Unexpected token type %s when expecting %s!\n", token.FileLine, token.FileColumn, FxTokenizer::GetTypeName(token.Type), + FxTokenizer::GetTypeName(token_type)); mHasErrors = true; } ++mTokenIndex; @@ -172,7 +174,7 @@ FxAstNode* FxConfigScript::TryParseKeyword(FxAstBlock* parent_block) if (hash == kw_action) { EatToken(TT::Identifier); - //ParseActionDeclare(); + // ParseActionDeclare(); return ParseActionDeclare(); } if (hash == kw_local) { @@ -261,7 +263,7 @@ FxAstVarDecl* FxConfigScript::InternalVarDeclare(FxTokenizer::Token* name_token, node->DefineAsGlobal = (scope == &mScopes[0]); // Push the variable to the scope - FxScriptVar var { name_token, type_token, scope }; + FxScriptVar var {name_token, type_token, scope}; scope->Vars.Insert(var); return node; @@ -282,7 +284,7 @@ FxAstVarDecl* FxConfigScript::ParseVarDeclare(FxScriptScope* scope) node->Type = &type; node->DefineAsGlobal = (scope == &mScopes[0]); - FxScriptVar var { &type, &name, scope }; + FxScriptVar var {&type, &name, scope}; node->Assignment = TryParseAssignment(node->Name); /*if (node->Assignment) { @@ -293,19 +295,19 @@ FxAstVarDecl* FxConfigScript::ParseVarDeclare(FxScriptScope* scope) return node; } -//FxScriptVar& FxConfigScript::ParseVarDeclare() +// FxScriptVar& FxConfigScript::ParseVarDeclare() //{ -// Token& type = EatToken(TT::Identifier); -// Token& name = EatToken(TT::Identifier); +// Token& type = EatToken(TT::Identifier); +// Token& name = EatToken(TT::Identifier); // -// FxScriptVar var{ name.GetHash(), &type, &name }; +// FxScriptVar var{ name.GetHash(), &type, &name }; // -// TryParseAssignment(var); +// TryParseAssignment(var); // -// mCurrentScope->Vars.Insert(var); +// mCurrentScope->Vars.Insert(var); // -// return mCurrentScope->Vars.GetLast(); -//} +// return mCurrentScope->Vars.GetLast(); +// } FxScriptVar* FxConfigScript::FindVar(FxHash hashed_name) { @@ -361,6 +363,19 @@ void FxConfigScript::Execute(FxScriptVM& vm) return; } printf("\n=====\n"); + + + FxScriptIREmitter ir_emitter; + ir_emitter.BeginEmitting(mRootBlock); + + printf("\n=====\n"); + + FxScriptIRPrinter ir_printer(ir_emitter.mBytecode); + + ir_printer.Print(); + + +#if 0 FxScriptBCEmitter emitter; emitter.BeginEmitting(mRootBlock); @@ -380,7 +395,7 @@ void FxConfigScript::Execute(FxScriptVM& vm) printf("Var(%u) AT %lld\n", handle.HashedName, handle.Offset); } - //return; + // return; vm.mExternalFuncs = mExternalFuncs; vm.Start(std::move(emitter.mBytecode)); @@ -390,24 +405,10 @@ void FxConfigScript::Execute(FxScriptVM& vm) } return; - /* - interpreter.Create(mRootBlock); - - // Copy any external variable declarations from the parser to the interpreter - FxScriptScope& global_scope = mScopes[0]; - FxScriptScope& interpreter_global_scope = interpreter.mScopes[0]; - - for (FxScriptVar& var : global_scope.Vars) { - if (var.IsExternal) { - interpreter_global_scope.Vars.Insert(var); - } - } - - interpreter.mExternalFuncs = mExternalFuncs; - - interpreter.Interpret();*/ +#endif } +#if 0 bool FxConfigScript::ExecuteUserCommand(const char* command, FxScriptInterpreter& interpreter) { mHasErrors = false; @@ -431,7 +432,7 @@ bool FxConfigScript::ExecuteUserCommand(const char* command, FxScriptInterpreter tokenizer.Tokenize(); for (FxTokenizer::Token& token : tokenizer.GetTokens()) { - //token.Print(); + // token.Print(); mTokens.Insert(token); } @@ -450,7 +451,7 @@ bool FxConfigScript::ExecuteUserCommand(const char* command, FxScriptInterpreter root_block->Statements.push_back(statement); } - //FxAstNode* node = ParseStatementAsCommand(); + // FxAstNode* node = ParseStatementAsCommand(); // Revert the current state if there have been errors if (root_block == nullptr) { @@ -485,6 +486,8 @@ bool FxConfigScript::ExecuteUserCommand(const char* command, FxScriptInterpreter return true; } +#endif + FxScriptValue FxConfigScript::ParseValue() { Token& token = GetToken(); @@ -515,7 +518,7 @@ FxScriptValue FxConfigScript::ParseValue() token.Print(); printf("\n"); - //printf("Undefined reference to variable \"%.*s\"! (Hash:%u)\n", token.Length, token.Start, token.GetHash()); + // printf("Undefined reference to variable \"%.*s\"! (Hash:%u)\n", token.Length, token.Start, token.GetHash()); EatToken(TT::Identifier); } } @@ -542,10 +545,10 @@ FxScriptValue FxConfigScript::ParseValue() return value; } -#define RETURN_IF_NO_TOKENS(rval_) \ - { \ - if (mTokenIndex >= mTokens.Size()) \ - return (rval_); \ +#define RETURN_IF_NO_TOKENS(rval_) \ + { \ + if (mTokenIndex >= mTokens.Size()) \ + return (rval_); \ } static bool IsTokenTypeLiteral(FxTokenizer::TokenType type) @@ -555,7 +558,6 @@ static bool IsTokenTypeLiteral(FxTokenizer::TokenType type) FxAstNode* FxConfigScript::ParseRhs() { - RETURN_IF_NO_TOKENS(nullptr); bool has_parameters = false; @@ -565,7 +567,8 @@ FxAstNode* FxConfigScript::ParseRhs() has_parameters = next_token_type == TT::LParen; if (mInCommandMode) { - has_parameters = next_token_type == TT::Identifier || next_token_type == TT::Integer || next_token_type == TT::Float || next_token_type == TT::String; + has_parameters = + next_token_type == TT::Identifier || next_token_type == TT::Integer || next_token_type == TT::Float || next_token_type == TT::String; } } @@ -587,7 +590,6 @@ FxAstNode* FxConfigScript::ParseRhs() if (action != nullptr) { lhs = ParseActionCall(); } - } } if (!lhs) { @@ -631,7 +633,8 @@ FxAstNode* FxConfigScript::ParseRhs() has_parameters = next_token_type == TT::LParen; if (mInCommandMode) { - has_parameters = next_token_type == TT::Identifier || next_token_type == TT::Integer || next_token_type == TT::Float || next_token_type == TT::String; + has_parameters = next_token_type == TT::Identifier || next_token_type == TT::Integer || next_token_type == TT::Float || next_token_type == + TT::String; } } @@ -693,7 +696,7 @@ FxAstAssign* FxConfigScript::TryParseAssignment(FxTokenizer::Token* var_name) var_ref->Scope = mCurrentScope; node->Var = var_ref; - //node->Value = ParseValue(); + // node->Value = ParseValue(); node->Rhs = ParseRhs(); return node; @@ -959,19 +962,19 @@ FxAstActionDecl* FxConfigScript::ParseActionDeclare() return node; } -//FxScriptValue FxConfigScript::TryCallInternalFunc(FxHash func_name, std::vector& params) +// FxScriptValue FxConfigScript::TryCallInternalFunc(FxHash func_name, std::vector& params) //{ -// FxScriptValue return_value; +// FxScriptValue return_value; // -// for (const FxScriptInternalFunc& func : mInternalFuncs) { -// if (func.HashedName == func_name) { -// func.Func(params, &return_value); -// return return_value; -// } -// } +// for (const FxScriptInternalFunc& func : mInternalFuncs) { +// if (func.HashedName == func_name) { +// func.Func(params, &return_value); +// return return_value; +// } +// } // -// return return_value; -//} +// return return_value; +// } FxAstActionCall* FxConfigScript::ParseActionCall() { @@ -1024,38 +1027,37 @@ FxAstActionCall* FxConfigScript::ParseActionCall() } - -//void FxConfigScript::ParseDoCall() +// void FxConfigScript::ParseDoCall() //{ -// Token& call_name = EatToken(TT::Identifier); +// Token& call_name = EatToken(TT::Identifier); // -// EatToken(TT::LParen); +// EatToken(TT::LParen); // -// std::vector params; +// std::vector params; // -// while (true) { -// params.push_back(ParseValue()); +// while (true) { +// params.push_back(ParseValue()); // -// if (GetToken().Type == TT::Comma) { -// EatToken(TT::Comma); -// continue; -// } +// if (GetToken().Type == TT::Comma) { +// EatToken(TT::Comma); +// continue; +// } // -// break; -// } +// break; +// } // -// EatToken(TT::RParen); +// EatToken(TT::RParen); // -// TryCallInternalFunc(call_name.GetHash(), params); +// TryCallInternalFunc(call_name.GetHash(), params); // -// printf("Calling "); -// call_name.Print(); +// printf("Calling "); +// call_name.Print(); // -// for (const auto& param : params) { -// printf("param : "); -// param.Print(); -// } -//} +// for (const auto& param : params) { +// printf("param : "); +// param.Print(); +// } +// } FxAstBlock* FxConfigScript::Parse() @@ -1082,276 +1084,19 @@ FxAstBlock* FxConfigScript::Parse() } - - -////////////////////////////////////////// -// Script Interpreter -////////////////////////////////////////// -//#if 0 -void FxScriptInterpreter::Create(FxAstBlock* root_block) -{ - mRootBlock = root_block; - - mScopes.Create(8); - mCurrentScope = mScopes.Insert(); - mCurrentScope->Parent = nullptr; - mCurrentScope->Vars.Create(FX_SCRIPT_SCOPE_LOCAL_VARS_START_SIZE); - mCurrentScope->Actions.Create(FX_SCRIPT_SCOPE_LOCAL_ACTIONS_START_SIZE); -} - - -void FxScriptInterpreter::Interpret() -{ - Visit(mRootBlock); - - mScopes[0].PrintAllVarsInScope(); -} - -void FxScriptInterpreter::PushScope() -{ - FxScriptScope* current = mCurrentScope; - - FxScriptScope* new_scope = mScopes.Insert(); - new_scope->Parent = current; - new_scope->Vars.Create(FX_SCRIPT_SCOPE_LOCAL_VARS_START_SIZE); - new_scope->Actions.Create(FX_SCRIPT_SCOPE_LOCAL_ACTIONS_START_SIZE); - - mCurrentScope = new_scope; -} - -void FxScriptInterpreter::PopScope() -{ - FxScriptScope* new_scope = mCurrentScope->Parent; - mScopes.RemoveLast(); - - assert(new_scope == &mScopes.GetLast()); - - mCurrentScope = new_scope; -} - -FxScriptVar* FxScriptInterpreter::FindVar(FxHash hashed_name) -{ - FxScriptScope* scope = mCurrentScope; - - while (scope) { - FxScriptVar* var = scope->FindVarInScope(hashed_name); - if (var) { - return var; - } - - scope = scope->Parent; - } - - return nullptr; -} - -FxScriptAction* FxScriptInterpreter::FindAction(FxHash hashed_name) -{ - FxScriptScope* scope = mCurrentScope; - - while (scope) { - FxScriptAction* var = scope->FindActionInScope(hashed_name); - if (var) { - return var; - } - - scope = scope->Parent; - } - - return nullptr; -} - -FxScriptExternalFunc* FxScriptInterpreter::FindExternalAction(FxHash hashed_name) -{ - for (FxScriptExternalFunc& func : mExternalFuncs) { - if (func.HashedName == hashed_name) { - return &func; - } - } - return nullptr; -} - -bool FxScriptInterpreter::CheckExternalCallArgs(FxAstActionCall* call, FxScriptExternalFunc& func) -{ - if (func.IsVariadic) { - return true; - } - - if (call->Params.size() != func.ParameterTypes.size()) { - return false; - } - - for (int i = 0; i < call->Params.size(); i++) { - FxScriptValue val = VisitRhs(call->Params[i]); - - if (!(val.Type & func.ParameterTypes[i])) { - return false; - } - } - - return true; -} - -FxScriptValue FxScriptInterpreter::VisitExternalCall(FxAstActionCall* call, FxScriptExternalFunc& func) -{ - FxScriptValue return_value; - - //PushScope(); - - if (!CheckExternalCallArgs(call, func)) { - printf("!!! Parameters do not match for function call!\n"); - PopScope(); - return return_value; - } - - std::vector params; - params.reserve(call->Params.size()); - - for (FxAstNode* param_node : call->Params) { - params.push_back(VisitRhs(param_node)); - } - - // func.Function(*this, params, &return_value); - - //PopScope(); - - return return_value; -} - -FxScriptValue FxScriptInterpreter::VisitActionCall(FxAstActionCall* call) -{ - FxScriptValue return_value; - - // This is not a local call, check for an internal function - if (call->Action == nullptr) { - for (FxScriptExternalFunc& func : mExternalFuncs) { - if (func.HashedName != call->HashedName) { - continue; - } - - return VisitExternalCall(call, func); - } - } - - if (call->Action == nullptr) { - puts("!!! Could not find action!"); - return return_value; - } - - PushScope(); - - std::vector param_decls = call->Action->Declaration->Params->Statements; - - if (call->Params.size() != param_decls.size()) { - printf("!!! MISMATCHED PARAM COUNTS\n"); - PopScope(); - - return return_value; - } - - // Assign each passed in value to the each parameter declaration - for (int i = 0; i < param_decls.size(); i++) { - FxAstVarDecl* decl = reinterpret_cast(param_decls[i]); - - FxScriptVar param(decl->Type, decl->Name, mCurrentScope); - param.Value = GetImmediateValue(VisitRhs(call->Params[i])); - - mCurrentScope->Vars.Insert(param); - } - - - if (call->Action->Declaration->ReturnVar) { - FxAstVarDecl* decl = call->Action->Declaration->ReturnVar; - - FxScriptVar return_var(decl->Type, decl->Name, mCurrentScope); - mCurrentScope->Vars.Insert(return_var); - - mCurrentScope->ReturnVar = &mCurrentScope->Vars.GetLast(); - - } - - Visit(call->Action->Block); - - // Acquire the return value from the scope - if (mCurrentScope->ReturnVar) { - return_value = GetImmediateValue(mCurrentScope->ReturnVar->Value); - } - - //mCurrentScope->PrintAllVarsInScope(); - - PopScope(); - - return return_value; -} - -FxScriptValue FxScriptInterpreter::VisitRhs(FxAstNode* node) -{ - if (node->NodeType == FX_AST_LITERAL) { - FxAstLiteral* literal = reinterpret_cast(node); - return literal->Value; - } - else if (node->NodeType == FX_AST_ACTIONCALL) { - FxAstActionCall* call = reinterpret_cast(node); - return VisitActionCall(call); - } - else if (node->NodeType == FX_AST_BINOP) { - FxAstBinop* binop = reinterpret_cast(node); - - FxScriptValue lhs_pre_val = VisitRhs(binop->Left); - FxScriptValue rhs_pre_val = VisitRhs(binop->Right); - - FxScriptValue lhs = GetImmediateValue(lhs_pre_val); - FxScriptValue rhs = GetImmediateValue(rhs_pre_val); - - float sign = (binop->OpToken->Type == TT::Plus) ? 1.0f : -1.0f; - - FxScriptValue result; - - if (lhs.Type == FxScriptValue::INT) { - result.ValueInt = lhs.ValueInt; - result.Type = FxScriptValue::INT; - - if (rhs.Type == FxScriptValue::INT) { - result.ValueInt += rhs.ValueInt * sign; - } - else if (rhs.Type == FxScriptValue::FLOAT) { - result.ValueInt += rhs.ValueFloat * sign; - } - } - else if (lhs.Type == FxScriptValue::FLOAT) { - result.ValueFloat = lhs.ValueFloat; - result.Type = FxScriptValue::FLOAT; - - if (rhs.Type == FxScriptValue::INT) { - result.ValueFloat += rhs.ValueInt * sign; - } - else if (rhs.Type == FxScriptValue::FLOAT) { - result.ValueFloat += rhs.ValueFloat * sign; - } - } - - return result; - } - - FxScriptValue value{}; - return value; -} - void FxConfigScript::DefineDefaultExternalFunctions() { // log([int | float | string | ref] args...) RegisterExternalFunc( - FxHashStr("log"), - {}, // Do not check argument types as we handle it here + FxHashStr("log"), {}, // Do not check argument types as we handle it here [](FxScriptVM* vm, std::vector& args, FxScriptValue* return_value) { printf("[SCRIPT]: "); for (int i = args.size() - 1; i >= 0; i--) { - FxScriptValue& arg = args[i]; - //const FxScriptValue& value = interpreter.GetImmediateValue(arg); + // const FxScriptValue& value = interpreter.GetImmediateValue(arg); const FxScriptValue& value = arg; switch (value.Type) { @@ -1377,343 +1122,82 @@ void FxConfigScript::DefineDefaultExternalFunctions() putchar('\n'); }, - true // Is variadic? + true // Is variadic? ); +} - // listvars() - //RegisterExternalFunc( - // FxHashStr("__listvars__"), - // {}, - // [](FxScriptVM* vm, std::vector& args, FxScriptValue* return_value) - // { - // FxScriptScope* scope = interpreter.mCurrentScope; - // // Since there is a new scope created on function call, we need to start from the parent scope - // if (scope && scope->Parent) { - // scope = scope->Parent; - // } - - // while (scope != nullptr) { - // scope->PrintAllVarsInScope(); - // scope = scope->Parent; - // } - // }, - // false - //); - - // listactions() - //RegisterExternalFunc( - // FxHashStr("__listactions__"), - // {}, - // [](FxScriptVM* vm, std::vector& args, FxScriptValue* return_value) - // { - // FxScriptScope* scope = interpreter.mCurrentScope; - // // Since there is a new scope created on function call, we need to start from the parent scope - // if (scope && scope->Parent) { - // scope = scope->Parent; - // } - - // while (scope != nullptr) { - - // for (const FxScriptAction& action : scope->Actions) { - // // Print out the action name - // printf("action %.*s", action.Declaration->Name->Length, action.Declaration->Name->Start); - - // // Retrieve the declarations for all parameters - // std::vector& param_decls = action.Declaration->Params->Statements; - // const size_t param_count = param_decls.size(); - - // // Print out the parameter list - // putchar('('); - - // for (int i = 0; i < param_count; i++) { - // FxAstNode* param_node = param_decls[i]; - // if (param_node->NodeType != FX_AST_VARDECL) { - // continue; - // } - - // FxAstVarDecl* param_decl = reinterpret_cast(param_node); - - // // Print the type of the parameter - // printf("%.*s ", param_decl->Type->Length, param_decl->Type->Start); - - // // Print the name of the parameter - // printf("%.*s", param_decl->Name->Length, param_decl->Name->Start); - - // // If there are more parameters following, output a comma - // if (i < param_count - 1) { - // printf(", "); - // } - // } - - // putchar(')'); - - // // Print out the return type at the end of the declaration if it exists - // if (action.Declaration->ReturnVar) { - // printf(" %.*s", action.Declaration->ReturnVar->Type->Length, action.Declaration->ReturnVar->Type->Start); - // } - - // putchar('\n'); - // } - - // scope = scope->Parent; - // } - // }, - // false - //); -} - -void FxScriptInterpreter::VisitAssignment(FxAstAssign* assign) -{ - FxScriptVar* var = FindVar(assign->Var->Name->GetHash()); - - if (!var) { - printf("!!! Could not find variable!\n"); - return; - } - constexpr FxHash builtin_int = FxHashStr("int"); - constexpr FxHash builtin_playerid = FxHashStr("playerid"); - constexpr FxHash builtin_float = FxHashStr("float"); - constexpr FxHash builtin_string = FxHashStr("string"); +void FxConfigScript::RegisterExternalFunc(FxHash func_name, std::vector param_types, + FxScriptExternalFunc::FuncType callback, bool is_variadic) +{ + FxScriptExternalFunc func { + .HashedName = func_name, + .Function = callback, + .ParameterTypes = param_types, + .IsVariadic = is_variadic, + }; - FxScriptValue rhs_value = VisitRhs(assign->Rhs); - const FxScriptValue& new_value = GetImmediateValue(rhs_value); + mExternalFuncs.push_back(func); +} - FxScriptValue::ValueType var_type = FxScriptValue::NONETYPE; - FxHash type_hash = var->Type->GetHash(); +///////////////////////////////////////// +// Script Bytecode Emitter +///////////////////////////////////////// - switch (type_hash) { - case builtin_playerid: - [[fallthrough]]; - case builtin_int: - var_type = FxScriptValue::INT; - break; - case builtin_float: - var_type = FxScriptValue::FLOAT; - break; - case builtin_string: - var_type = FxScriptValue::STRING; - break; - default: - printf("!!! Unknown type for variable %.*s!\n", var->Type->Length, var->Type->Start); - return; - } +#pragma region BytecodeEmitter - if (var_type != new_value.Type) { - printf("!!! Assignment value type does not match variable type!\n"); - return; - } +#include "FxScriptBytecode.hpp" +void FxScriptBCEmitter::BeginEmitting(FxAstNode* node) +{ + mStackSize = 1024; - var->Value = new_value; + /*mStack = new uint8[1024]; + mStackStart = mStack;*/ - //puts("Visit Assign"); -} + mBytecode.Create(4096); + VarHandles.Create(64); -void FxScriptInterpreter::Visit(FxAstNode* node) -{ - if (node == nullptr) { - return; - } + Emit(node); - if (node->NodeType == FX_AST_BLOCK) { - //puts("Visit Block"); + printf("\n"); - FxAstBlock* block = reinterpret_cast(node); - for (FxAstNode* child : block->Statements) { - if (child->NodeType == FX_AST_RETURN) { - break; - } + PrintBytecode(); +} - Visit(child); - } +#define RETURN_IF_NO_NODE(node_) \ + if ((node_) == nullptr) { \ + return; \ } - else if (node->NodeType == FX_AST_ACTIONDECL) { - FxAstActionDecl* actiondecl = reinterpret_cast(node); - //puts("Visit ActionDecl"); - FxScriptAction action(actiondecl->Name, mCurrentScope, actiondecl->Block, actiondecl); - mCurrentScope->Actions.Insert(action); - - //Visit(actiondecl->Block); +#define RETURN_VALUE_IF_NO_NODE(node_, value_) \ + if ((node_) == nullptr) { \ + return (value_); \ } - else if (node->NodeType == FX_AST_VARDECL) { - FxAstVarDecl* vardecl = reinterpret_cast(node); - //puts("Visit VarDecl"); - - FxScriptScope* scope = mCurrentScope; - if (vardecl->DefineAsGlobal) { - scope = &mScopes[0]; - } - FxScriptVar var(vardecl->Type, vardecl->Name, scope); - scope->Vars.Insert(var); +void FxScriptBCEmitter::Emit(FxAstNode* node) +{ + RETURN_IF_NO_NODE(node); - Visit(vardecl->Assignment); + if (node->NodeType == FX_AST_BLOCK) { + return EmitBlock(reinterpret_cast(node)); } - else if (node->NodeType == FX_AST_ASSIGN) { - FxAstAssign* assign = reinterpret_cast(node); - VisitAssignment(assign); + else if (node->NodeType == FX_AST_ACTIONDECL) { + return EmitAction(reinterpret_cast(node)); } else if (node->NodeType == FX_AST_ACTIONCALL) { - FxAstActionCall* actioncall = reinterpret_cast(node); - FxScriptValue return_value = VisitActionCall(actioncall); - - // If we are in command mode, print the result to the user - if (mInCommandMode && return_value.Type != FxScriptValue::NONETYPE) { - return_value.Print(); - } - } - // If we are in command mode, print the variable to the user - else if (node->NodeType == FX_AST_VARREF && mInCommandMode) { - FxAstVarRef* ref = reinterpret_cast(node); - FxScriptVar* var = FindVar(ref->Name->GetHash()); - - if (var) { - var->Print(); - } - } - // If we are in command mode, print the literal(probably result) to the user - else if (node->NodeType == FX_AST_LITERAL && mInCommandMode) { - FxAstLiteral* literal = reinterpret_cast(node); - GetImmediateValue(literal->Value).Print(); + return DoActionCall(reinterpret_cast(node)); } - // Executes a statement in command mode - else if (node->NodeType == FX_AST_COMMANDMODE) { - mInCommandMode = true; - Visit(reinterpret_cast(node)->Node); - mInCommandMode = false; + else if (node->NodeType == FX_AST_ASSIGN) { + return EmitAssign(reinterpret_cast(node)); } - else { - puts("[UNKNOWN]"); + else if (node->NodeType == FX_AST_VARDECL) { + DoVarDeclare(reinterpret_cast(node)); + return; } -} - -void FxScriptInterpreter::DefineExternalVar(const char* type, const char* name, const FxScriptValue& value) -{ - Token* name_token = FX_SCRIPT_ALLOC_MEMORY(Token, sizeof(Token)); - Token* type_token = FX_SCRIPT_ALLOC_MEMORY(Token, sizeof(Token)); - - { - const uint32 type_len = strlen(type); - char* type_buffer = FX_SCRIPT_ALLOC_MEMORY(char, (type_len + 1)); - std::strcpy(type_buffer, type); - //type_buffer[type_len + 1] = 0; - - - type_token->Start = type_buffer; - type_token->Type = TT::Identifier; - type_token->Start[type_len] = 0; - type_token->Length = type_len + 1; - } - - { - const uint32 name_len = strlen(name); - - char* name_buffer = FX_SCRIPT_ALLOC_MEMORY(char, (name_len + 1)); - std::strcpy(name_buffer, name); - - name_token->Start = name_buffer; - name_token->Type = TT::Identifier; - name_token->Start[name_len] = 0; - name_token->Length = name_len + 1; - } - - FxScriptScope* definition_scope = &mScopes[0]; - - FxScriptVar var(type_token, name_token, definition_scope, true); - var.Value = value; - - definition_scope->Vars.Insert(var); -} - -const FxScriptValue& FxScriptInterpreter::GetImmediateValue(const FxScriptValue& value) -{ - // If the value is a reference, get the value of that reference - if (value.Type == FxScriptValue::REF) { - FxScriptVar* var = FindVar(value.ValueRef->Name->GetHash()); - - if (!var) { - printf("!!! Undefined reference to variable\n"); - //value.ValueRef->Name->Print(); - putchar('\n'); - - return FxScriptValue::None; - } - - return var->Value; - } - - return value; -} - -//#endif - -void FxConfigScript::RegisterExternalFunc(FxHash func_name, std::vector param_types, FxScriptExternalFunc::FuncType callback, bool is_variadic) -{ - FxScriptExternalFunc func{ - .HashedName = func_name, - .Function = callback, - .ParameterTypes = param_types, - .IsVariadic = is_variadic, - }; - - mExternalFuncs.push_back(func); -} - - -///////////////////////////////////////// -// Script Bytecode Emitter -///////////////////////////////////////// - -#include "FxScriptBytecode.hpp" - -void FxScriptBCEmitter::BeginEmitting(FxAstNode* node) -{ - mStackSize = 1024; - - /*mStack = new uint8[1024]; - mStackStart = mStack;*/ - - mBytecode.Create(4096); - VarHandles.Create(64); - - Emit(node); - - printf("\n"); - - PrintBytecode(); -} - -#define RETURN_IF_NO_NODE(node_) \ - if ((node_) == nullptr) { return; } - -#define RETURN_VALUE_IF_NO_NODE(node_, value_) \ - if ((node_) == nullptr) { return (value_); } - -void FxScriptBCEmitter::Emit(FxAstNode* node) -{ - RETURN_IF_NO_NODE(node); - - if (node->NodeType == FX_AST_BLOCK) { - return EmitBlock(reinterpret_cast(node)); - } - else if (node->NodeType == FX_AST_ACTIONDECL) { - return EmitAction(reinterpret_cast(node)); - } - else if (node->NodeType == FX_AST_ACTIONCALL) { - return DoActionCall(reinterpret_cast(node)); - } - else if (node->NodeType == FX_AST_ASSIGN) { - return EmitAssign(reinterpret_cast(node)); - } - else if (node->NodeType == FX_AST_VARDECL) { - DoVarDeclare(reinterpret_cast(node)); - return; - } - else if (node->NodeType == FX_AST_RETURN) { - constexpr FxHash return_val_hash = FxHashStr(FX_SCRIPT_VAR_RETURN_VAL); + else if (node->NodeType == FX_AST_RETURN) { + constexpr FxHash return_val_hash = FxHashStr(FX_SCRIPT_VAR_RETURN_VAL); FxScriptBytecodeVarHandle* return_var = FindVarHandle(return_val_hash); @@ -1748,7 +1232,6 @@ FxScriptBytecodeActionHandle* FxScriptBCEmitter::FindActionHandle(FxHash hashed_ } - FxScriptRegister FxScriptBCEmitter::FindFreeRegister() { uint16 gp_r = 0x01; @@ -1862,8 +1345,14 @@ void FxScriptBCEmitter::WriteOp(uint8 op_base, uint8 op_spec) using RhsMode = FxScriptBCEmitter::RhsMode; -#define MARK_REGISTER_USED(regn_) { MarkRegisterUsed(regn_); } -#define MARK_REGISTER_FREE(regn_) { MarkRegisterFree(regn_); } +#define MARK_REGISTER_USED(regn_) \ + { \ + MarkRegisterUsed(regn_); \ + } +#define MARK_REGISTER_FREE(regn_) \ + { \ + MarkRegisterFree(regn_); \ + } void FxScriptBCEmitter::MarkRegisterUsed(FxScriptRegister reg) { @@ -2017,7 +1506,6 @@ void FxScriptBCEmitter::EmitType(FxScriptValue::ValueType type) uint32 FxScriptBCEmitter::EmitDataString(char* str, uint16 length) { - WriteOp(OpBase_Data, OpSpecData_String); uint32 start_index = mBytecode.Size(); @@ -2186,7 +1674,7 @@ void FxScriptBCEmitter::EmitAssign(FxAstAssign* assign) // force_absolute_save = true; // } - //int output_offset = -(static_cast(mStackOffset) - static_cast(var_handle->Offset)); + // int output_offset = -(static_cast(mStackOffset) - static_cast(var_handle->Offset)); if (!var_handle) { printf("Could not find var handle to assign to!"); @@ -2207,10 +1695,10 @@ FxScriptRegister FxScriptBCEmitter::EmitLiteralInt(FxAstLiteral* literal, RhsMod // If this is as a literal, push the value to the stack and pop onto the target register. else if (mode == RhsMode::RHS_FETCH_TO_REGISTER) { - //EmitPush32(literal->Value.ValueInt); + // EmitPush32(literal->Value.ValueInt); FxScriptRegister output_reg = FindFreeRegister(); - //EmitPop32(output_reg); + // EmitPop32(output_reg); EmitMoveInt32(output_reg, literal->Value.ValueInt); @@ -2253,11 +1741,11 @@ FxScriptRegister FxScriptBCEmitter::EmitLiteralString(FxAstLiteral* literal, Rhs EmitType(FxScriptValue::STRING); // Push the string position - //EmitPush32(string_position); + // EmitPush32(string_position); // Find a register to output to and write the index FxScriptRegister output_reg = FindFreeRegister(); - //EmitPop32(output_reg); + // EmitPop32(output_reg); EmitMoveInt32(output_reg, string_position); @@ -2377,7 +1865,7 @@ FxScriptBytecodeVarHandle* FxScriptBCEmitter::DoVarDeclare(FxAstVarDecl* decl, V break; }; - FxScriptBytecodeVarHandle handle{ + FxScriptBytecodeVarHandle handle { .HashedName = decl->Name->GetHash(), .Type = value_type, // Just int for now .Offset = (mStackOffset), @@ -2431,7 +1919,7 @@ void FxScriptBCEmitter::DoActionCall(FxAstActionCall* call) EmitRhs(param, RhsMode::RHS_DEFINE_IN_MEMORY, nullptr); call_locations.push_back(mStackOffset - 4); } - //MARK_REGISTER_FREE(reg); + // MARK_REGISTER_FREE(reg); } EmitPush32r(FX_REG_RA); @@ -2520,7 +2008,7 @@ void FxScriptBCEmitter::EmitAction(FxAstActionDecl* action) // Emit the jump instruction, we will update the jump position after emitting all of the code inside the block EmitJumpRelative(0); - //const uint32 initial_stack_offset = mStackOffset; + // const uint32 initial_stack_offset = mStackOffset; const size_t header_jump_start_index = start_of_action + sizeof(uint16); @@ -2569,10 +2057,7 @@ void FxScriptBCEmitter::EmitAction(FxAstActionDecl* action) mBytecode[header_jump_start_index] = static_cast(distance_to_action >> 8); mBytecode[header_jump_start_index + 1] = static_cast((distance_to_action & 0xFF)); - FxScriptBytecodeActionHandle action_handle{ - .HashedName = action->Name->GetHash(), - .BytecodeIndex = static_cast(start_of_action + 4) - }; + FxScriptBytecodeActionHandle action_handle {.HashedName = action->Name->GetHash(), .BytecodeIndex = static_cast(start_of_action + 4)}; const size_t number_of_scope_var_handles = VarHandles.Size() - start_var_handle_count; printf("Number of var handles to remove: %zu\n", number_of_scope_var_handles); @@ -2620,6 +2105,7 @@ void FxScriptBCEmitter::PrintBytecode() printf("\n"); } +#pragma endregion BytecodeEmitter ///////////////////////////////////// @@ -2687,13 +2173,13 @@ void FxScriptBCPrinter::DoArith(char* s, uint8 op_base, uint8 op_spec) uint8 b_reg = mBytecode[mBytecodeIndex++]; if (op_spec == OpSpecArith_Add) { - BC_PRINT_OP("add32 %s, %s", FxScriptBCEmitter::GetRegisterName(static_cast(a_reg)), FxScriptBCEmitter::GetRegisterName(static_cast(b_reg))); + BC_PRINT_OP("add32 %s, %s", FxScriptBCEmitter::GetRegisterName(static_cast(a_reg)), + FxScriptBCEmitter::GetRegisterName(static_cast(b_reg))); } } void FxScriptBCPrinter::DoSave(char* s, uint8 op_base, uint8 op_spec) { - // Save a imm32 into an offset in the stack if (op_spec == OpSpecSave_Int32) { const int16 offset = Read16(); @@ -2847,11 +2333,9 @@ void FxScriptBCPrinter::PrintOp() printf("%-25s", s); printf("\t# Offset: %u\n", bc_index); - } - /////////////////////////////////////////// // Bytecode VM /////////////////////////////////////////// @@ -2859,8 +2343,7 @@ void FxScriptBCPrinter::PrintOp() void FxScriptVM::PrintRegisters() { printf("\n=== Register Dump ===\n\n"); - printf("X0=%u\tX1=%u\tX2=%u\tX3=%u\n", - Registers[FX_REG_X0], Registers[FX_REG_X1], Registers[FX_REG_X2], Registers[FX_REG_X3]); + printf("X0=%u\tX1=%u\tX2=%u\tX3=%u\n", Registers[FX_REG_X0], Registers[FX_REG_X1], Registers[FX_REG_X2], Registers[FX_REG_X3]); printf("XR=%u\tRA=%u\n", Registers[FX_REG_XR], Registers[FX_REG_RA]); @@ -2912,7 +2395,6 @@ uint32 FxScriptVM::Pop32() } - FxScriptVMCallFrame& FxScriptVM::PushCallFrame() { mIsInCallFrame = true; @@ -2927,7 +2409,6 @@ void FxScriptVM::PopCallFrame() { FxScriptVMCallFrame* frame = GetCurrentCallFrame(); if (!frame) { - FX_BREAKPOINT; } @@ -3108,7 +2589,6 @@ void FxScriptVM::DoSave(uint8 op_base, uint8 op_spec) void FxScriptVM::DoJump(uint8 op_base, uint8 op_spec) { - if (op_spec == OpSpecJump_Relative) { uint16 offset = Read16(); mPC += offset; @@ -3123,9 +2603,9 @@ void FxScriptVM::DoJump(uint8 op_base, uint8 op_spec) } else if (op_spec == OpSpecJump_CallAbsolute) { uint32 call_address = Read32(); - //printf("Call to address % 4u\n", call_address); + // printf("Call to address % 4u\n", call_address); - //Push32(mPC); + // Push32(mPC); Registers[FX_REG_RA] = mPC; @@ -3140,14 +2620,14 @@ void FxScriptVM::DoJump(uint8 op_base, uint8 op_spec) else if (op_spec == OpSpecJump_ReturnToCaller) { PopCallFrame(); - //uint32 return_address = Pop32(); + // uint32 return_address = Pop32(); uint32 return_address = Registers[FX_REG_RA]; - //printf("Return to caller (%04d)\n", return_address); + // printf("Return to caller (%04d)\n", return_address); mPC = return_address; // Restore the return address register to its previous value. This is pushed when `paramsstart` is encountered. - //Registers[FX_REG_RA] = Pop32(); + // Registers[FX_REG_RA] = Pop32(); } else if (op_spec == OpSpecJump_CallExternal) { uint32 hashed_name = Read32(); @@ -3195,7 +2675,7 @@ void FxScriptVM::DoJump(uint8 op_base, uint8 op_spec) mPushedTypes.Clear(); mIsInParams = false; - FxScriptValue return_value{}; + FxScriptValue return_value {}; external_func->Function(this, params, &return_value); } } @@ -3211,7 +2691,7 @@ void FxScriptVM::DoData(uint8 op_base, uint8 op_spec) // Push the current return address pointer. This is so nested action calls can correctly navigate back // to the caller. - //Push32(Registers[FX_REG_RA]); + // Push32(Registers[FX_REG_RA]); } } @@ -3237,7 +2717,6 @@ void FxScriptVM::DoMove(uint8 op_base, uint8 op_spec_raw) } - ////////////////////////////////////////////////// // Script Bytecode to x86 Transpiler ////////////////////////////////////////////////// @@ -3280,7 +2759,7 @@ static const char* GetX86Register(FxScriptRegister reg) return "UNKNOWN"; } -//#define BC_PRINT_OP(fmt_, ...) snprintf(s, 128, fmt_, ##__VA_ARGS__) +// #define BC_PRINT_OP(fmt_, ...) snprintf(s, 128, fmt_, ##__VA_ARGS__) void FxScriptTranspilerX86::DoLoad(char* s, uint8 op_base, uint8 op_spec_raw) { @@ -3295,9 +2774,8 @@ void FxScriptTranspilerX86::DoLoad(char* s, uint8 op_base, uint8 op_spec_raw) } else if (op_spec == OpSpecLoad_AbsoluteInt32) { uint32 offset = Read32(); - //StrOut("load32a %u, %s", offset, GetX86Register(static_cast(op_reg))); + // StrOut("load32a %u, %s", offset, GetX86Register(static_cast(op_reg))); StrOut("mov %s, [esi + %u]", GetX86Register(static_cast(op_reg)), offset); - } } @@ -3343,14 +2821,13 @@ void FxScriptTranspilerX86::DoArith(char* s, uint8 op_base, uint8 op_spec) void FxScriptTranspilerX86::DoSave(char* s, uint8 op_base, uint8 op_spec) { - // Save a imm32 into an offset in the stack if (op_spec == OpSpecSave_Int32) { const int16 offset = Read16() + 8; const int32 value = Read32(); StrOut("mov dword [ebp %c %d], %d", (offset <= 0 ? '+' : '-'), abs(offset), value); - //BC_PRINT_OP("save32 %d, %u", offset, value); + // BC_PRINT_OP("save32 %d, %u", offset, value); } // Save a register into an offset in the stack @@ -3361,20 +2838,20 @@ void FxScriptTranspilerX86::DoSave(char* s, uint8 op_base, uint8 op_spec) offset += 8; StrOut("mov [ebp %c %d], %s", (offset <= 0 ? '+' : '-'), abs(offset), GetX86Register(static_cast(reg))); - //BC_PRINT_OP("save32r %d, %s", offset, GetX86Register(static_cast(reg))); + // BC_PRINT_OP("save32r %d, %s", offset, GetX86Register(static_cast(reg))); } else if (op_spec == OpSpecSave_AbsoluteInt32) { const uint32 offset = Read32(); const int32 value = Read32(); - //StrOut("save32a %u, %u", offset, value); + // StrOut("save32a %u, %u", offset, value); StrOut("mov [esi %c %d], %d", (offset <= 0 ? '+' : '-'), offset, value); } else if (op_spec == OpSpecSave_AbsoluteReg32) { const uint32 offset = Read32(); uint16 reg = Read16(); - //StrOut("save32ar %u, %s", offset, GetX86Register(static_cast(reg))); + // StrOut("save32ar %u, %s", offset, GetX86Register(static_cast(reg))); StrOut("mov [esi %c %d], %s", (offset <= 0 ? '+' : '-'), offset, GetX86Register(static_cast(reg))); } } @@ -3411,7 +2888,7 @@ void FxScriptTranspilerX86::DoJump(char* s, uint8 op_base, uint8 op_spec) } else if (op_spec == OpSpecJump_CallAbsolute) { uint32 position = Read32(); - //BC_PRINT_OP("calla %u", position); + // BC_PRINT_OP("calla %u", position); StrOut("call _L_%u", position); } else if (op_spec == OpSpecJump_ReturnToCaller) { @@ -3431,7 +2908,7 @@ void FxScriptTranspilerX86::DoJump(char* s, uint8 op_base, uint8 op_spec) } else if (op_spec == OpSpecJump_CallExternal) { uint32 hashed_name = Read32(); - //StrOut("callext %u", hashed_name); + // StrOut("callext %u", hashed_name); StrOut("nop ; callext %u", hashed_name); } @@ -3457,17 +2934,17 @@ void FxScriptTranspilerX86::DoData(char* s, uint8 op_base, uint8 op_spec) } else if (op_spec == OpSpecData_ParamsStart) { StrOut("; Parameters start"); - //BC_PRINT_OP("paramsstart"); + // BC_PRINT_OP("paramsstart"); } } void FxScriptTranspilerX86::DoType(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == OpSpecType_Int) { - //BC_PRINT_OP("typeint"); + // BC_PRINT_OP("typeint"); } else if (op_spec == OpSpecType_String) { - //BC_PRINT_OP("typestr"); + // BC_PRINT_OP("typestr"); } } @@ -3478,7 +2955,7 @@ void FxScriptTranspilerX86::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) if (op_spec == OpSpecMove_Int32) { int32 value = Read32(); - //StrOut("move32 %s, %u", FxScriptBCEmitter::GetRegisterName(op_reg), value); + // StrOut("move32 %s, %u", FxScriptBCEmitter::GetRegisterName(op_reg), value); StrOut("mov %s, %d", GetX86Register(op_reg), value); } } @@ -3559,6 +3036,1196 @@ void FxScriptTranspilerX86::PrintOp() DoMove(s, op_base, op_spec); break; } - //printf("%-25s\n", s); + // printf("%-25s\n", s); +} + + +#pragma region IrEmitter + +#include "FxScriptBytecode.hpp" + +void FxScriptIREmitter::BeginEmitting(FxAstNode* node) +{ + mStackSize = 1024; + + /*mStack = new uint8[1024]; + mStackStart = mStack;*/ + + mBytecode.Create(4096); + VarHandles.Create(64); + + Emit(node); + + printf("\n"); + + PrintBytecode(); +} + +#define RETURN_IF_NO_NODE(node_) \ + if ((node_) == nullptr) { \ + return; \ + } + +#define RETURN_VALUE_IF_NO_NODE(node_, value_) \ + if ((node_) == nullptr) { \ + return (value_); \ + } + +void FxScriptIREmitter::Emit(FxAstNode* node) +{ + RETURN_IF_NO_NODE(node); + + if (node->NodeType == FX_AST_BLOCK) { + return EmitBlock(reinterpret_cast(node)); + } + else if (node->NodeType == FX_AST_ACTIONDECL) { + return EmitAction(reinterpret_cast(node)); + } + else if (node->NodeType == FX_AST_ACTIONCALL) { + return DoActionCall(reinterpret_cast(node)); + } + else if (node->NodeType == FX_AST_ASSIGN) { + return EmitAssign(reinterpret_cast(node)); + } + else if (node->NodeType == FX_AST_VARDECL) { + DoVarDeclare(reinterpret_cast(node)); + return; + } + else if (node->NodeType == FX_AST_RETURN) { + constexpr FxHash return_val_hash = FxHashStr(FX_SCRIPT_VAR_RETURN_VAL); + + FxScriptBytecodeVarHandle* return_var = FindVarHandle(return_val_hash); + + if (return_var) { + DoLoad(return_var->Offset, FX_REG_XR); + } + + EmitJumpReturnToCaller(); + + return; + } +} + +FxScriptBytecodeVarHandle* FxScriptIREmitter::FindVarHandle(FxHash hashed_name) +{ + for (FxScriptBytecodeVarHandle& handle : VarHandles) { + if (handle.HashedName == hashed_name) { + return &handle; + } + } + return nullptr; +} + +FxScriptBytecodeActionHandle* FxScriptIREmitter::FindActionHandle(FxHash hashed_name) +{ + for (FxScriptBytecodeActionHandle& handle : ActionHandles) { + if (handle.HashedName == hashed_name) { + return &handle; + } + } + return nullptr; +} + + +FxScriptRegister FxScriptIREmitter::FindFreeRegister() +{ + uint16 gp_r = 0x01; + + const uint16 num_gp_regs = FX_REG_X3; + + for (int i = 0; i < num_gp_regs; i++) { + if (!(mRegsInUse & gp_r)) { + // We are starting on 0x01, so register index should be N + 1 + const int register_index = i + 1; + + return static_cast(register_index); + } + + gp_r <<= 1; + } + + return FxScriptRegister::FX_REG_NONE; +} + +const char* FxScriptIREmitter::GetRegisterName(FxScriptRegister reg) +{ + switch (reg) { + case FX_REG_NONE: + return "NONE"; + case FX_REG_X0: + return "X0"; + case FX_REG_X1: + return "X1"; + case FX_REG_X2: + return "X2"; + case FX_REG_X3: + return "X3"; + case FX_REG_RA: + return "RA"; + case FX_REG_XR: + return "XR"; + case FX_REG_SP: + return "SP"; + default:; + }; + + return "NONE"; +} +FxScriptRegister FxScriptIREmitter::RegFlagToReg(FxScriptRegisterFlag reg_flag) +{ + switch (reg_flag) { + case FX_REGFLAG_NONE: + return FX_REG_NONE; + case FX_REGFLAG_X0: + return FX_REG_X0; + case FX_REGFLAG_X1: + return FX_REG_X1; + case FX_REGFLAG_X2: + return FX_REG_X2; + case FX_REGFLAG_X3: + return FX_REG_X3; + case FX_REGFLAG_RA: + return FX_REG_RA; + case FX_REGFLAG_XR: + return FX_REG_XR; + } + + return FX_REG_NONE; +} + +FxScriptRegisterFlag FxScriptIREmitter::RegToRegFlag(FxScriptRegister reg) +{ + switch (reg) { + case FX_REG_NONE: + return FX_REGFLAG_NONE; + case FX_REG_X0: + return FX_REGFLAG_X0; + case FX_REG_X1: + return FX_REGFLAG_X1; + case FX_REG_X2: + return FX_REGFLAG_X2; + case FX_REG_X3: + return FX_REGFLAG_X3; + case FX_REG_RA: + return FX_REGFLAG_RA; + case FX_REG_XR: + return FX_REGFLAG_XR; + case FX_REG_SP: + return FX_REGFLAG_NONE; + default:; + } + + return FX_REGFLAG_NONE; +} + + +void FxScriptIREmitter::Write16(uint16 value) +{ + mBytecode.Insert(static_cast(value >> 8)); + mBytecode.Insert(static_cast(value)); +} + +void FxScriptIREmitter::Write32(uint32 value) +{ + Write16(static_cast(value >> 16)); + Write16(static_cast(value)); +} + +void FxScriptIREmitter::WriteOp(uint8 op_base, uint8 op_spec) +{ + mBytecode.Insert(op_base); + mBytecode.Insert(op_spec); +} + +using IRRhsMode = FxScriptIREmitter::RhsMode; + +#define MARK_REGISTER_USED(regn_) \ + { \ + MarkRegisterUsed(regn_); \ + } +#define MARK_REGISTER_FREE(regn_) \ + { \ + MarkRegisterFree(regn_); \ + } + +void FxScriptIREmitter::MarkRegisterUsed(FxScriptRegister reg) +{ + FxScriptRegisterFlag rflag = RegToRegFlag(reg); + mRegsInUse = static_cast(uint16(mRegsInUse) | uint16(rflag)); +} + +void FxScriptIREmitter::MarkRegisterFree(FxScriptRegister reg) +{ + FxScriptRegisterFlag rflag = RegToRegFlag(reg); + + mRegsInUse = static_cast(uint16(mRegsInUse) & (~uint16(rflag))); +} + +void FxScriptIREmitter::EmitSave32(int16 offset, uint32 value) +{ + // SAVE32 [i16 offset] [i32] + WriteOp(IrBase_Save, IrSpecSave_Int32); + + Write16(offset); + Write32(value); +} + +void FxScriptIREmitter::EmitSaveReg32(int16 offset, FxScriptRegister reg) +{ + // SAVE32r [i16 offset] [%r32] + WriteOp(IrBase_Save, IrSpecSave_Reg32); + + Write16(offset); + Write16(reg); +} + + +void FxScriptIREmitter::EmitSaveAbsolute32(uint32 position, uint32 value) +{ + // SAVE32a [i32 offset] [i32] + WriteOp(IrBase_Save, IrSpecSave_AbsoluteInt32); + + Write32(position); + Write32(value); +} + +void FxScriptIREmitter::EmitSaveAbsoluteReg32(uint32 position, FxScriptRegister reg) +{ + // SAVE32r [i32 offset] [%r32] + WriteOp(IrBase_Save, IrSpecSave_AbsoluteReg32); + + Write32(position); + Write16(reg); +} + +void FxScriptIREmitter::EmitPush32(uint32 value) +{ + // PUSH32 [i32] + WriteOp(IrBase_Push, IrSpecPush_Int32); + Write32(value); + + mStackOffset += 4; +} + +void FxScriptIREmitter::EmitPush32r(FxScriptRegister reg) +{ + // PUSH32r [%r32] + WriteOp(IrBase_Push, IrSpecPush_Reg32); + Write16(reg); + + mStackOffset += 4; +} + + +void FxScriptIREmitter::EmitPop32(FxScriptRegister output_reg) +{ + // POP32 [%r32] + WriteOp(IrBase_Pop, (IrSpecPop_Int32 << 4) | (output_reg & 0x0F)); + + mStackOffset -= 4; +} + +void FxScriptIREmitter::EmitLoad32(int offset, FxScriptRegister output_reg) +{ + // LOAD [i16] [%r32] + WriteOp(IrBase_Load, (IrSpecLoad_Int32 << 4) | (output_reg & 0x0F)); + Write16(static_cast(offset)); +} + +void FxScriptIREmitter::EmitLoadAbsolute32(uint32 position, FxScriptRegister output_reg) +{ + // LOADA [i32] [%r32] + WriteOp(IrBase_Load, (IrSpecLoad_AbsoluteInt32 << 4) | (output_reg & 0x0F)); + Write32(position); +} + +void FxScriptIREmitter::EmitJumpRelative(uint16 offset) +{ + WriteOp(IrBase_Jump, IrSpecJump_Relative); + Write16(offset); +} + +void FxScriptIREmitter::EmitJumpAbsolute(uint32 position) +{ + WriteOp(IrBase_Jump, IrSpecJump_Absolute); + Write32(position); +} + + +void FxScriptIREmitter::EmitJumpAbsoluteReg32(FxScriptRegister reg) +{ + WriteOp(IrBase_Jump, IrSpecJump_AbsoluteReg32); + Write16(reg); +} + +void FxScriptIREmitter::EmitJumpCallAbsolute(uint32 position) +{ + WriteOp(IrBase_Jump, IrSpecJump_CallAbsolute); + Write32(position); +} + + +void FxScriptIREmitter::EmitJumpCallExternal(FxHash hashed_name) +{ + WriteOp(IrBase_Jump, IrSpecJump_CallExternal); + Write32(hashed_name); +} + +void FxScriptIREmitter::EmitJumpReturnToCaller() +{ + WriteOp(IrBase_Jump, IrSpecJump_ReturnToCaller); +} + +void FxScriptIREmitter::EmitMoveInt32(FxScriptRegister reg, uint32 value) +{ + WriteOp(IrBase_Move, (IrSpecMove_Int32 << 4) | (reg & 0x0F)); + Write32(value); +} + +void FxScriptIREmitter::EmitParamsStart() +{ + WriteOp(IrBase_Data, IrSpecData_ParamsStart); +} + +void FxScriptIREmitter::EmitType(FxScriptValue::ValueType type) +{ + IrSpecType op_type = IrSpecType_Int; + + if (type == FxScriptValue::STRING) { + op_type = IrSpecType_String; + } + + WriteOp(IrBase_Type, op_type); +} + +uint32 FxScriptIREmitter::EmitDataString(char* str, uint16 length) +{ + WriteOp(IrBase_Data, IrSpecData_String); + + uint32 start_index = mBytecode.Size(); + + uint16 final_length = length + 1; + + // If the length is not a factor of 2 (sizeof uint16) then add a byte of padding + if ((final_length & 0x01)) { + ++final_length; + } + + Write16(final_length); + + for (int i = 0; i < final_length; i += 2) { + mBytecode.Insert(str[i]); + + if (i >= length) { + mBytecode.Insert(0); + break; + } + + mBytecode.Insert(str[i + 1]); + } + + return start_index; +} + + +FxScriptRegister FxScriptIREmitter::EmitBinop(FxAstBinop* binop, FxScriptBytecodeVarHandle* handle) +{ + bool will_preserve_lhs = false; + // Load the A and B values into the registers + FxScriptRegister a_reg = EmitRhs(binop->Left, RhsMode::RHS_FETCH_TO_REGISTER, handle); + + // Since there is a chance that this register will be clobbered (by binop, action call, etc), we will + // push the value of the register here and return it after processing the RHS + if (binop->Right->NodeType != FX_AST_LITERAL) { + will_preserve_lhs = true; + EmitPush32r(a_reg); + } + + FxScriptRegister b_reg = EmitRhs(binop->Right, RhsMode::RHS_FETCH_TO_REGISTER, handle); + + // Retrieve the previous LHS + if (will_preserve_lhs) { + EmitPop32(a_reg); + } + + if (binop->OpToken->Type == TT::Plus) { + WriteOp(IrBase_Arith, IrSpecArith_Add); + + mBytecode.Insert(a_reg); + mBytecode.Insert(b_reg); + } + + // We no longer need the lhs or rhs registers, free em + MARK_REGISTER_FREE(a_reg); + MARK_REGISTER_FREE(b_reg); + + return FX_REG_XR; +} + +FxScriptRegister FxScriptIREmitter::EmitVarFetch(FxAstVarRef* ref, RhsMode mode) +{ + FxScriptBytecodeVarHandle* var_handle = FindVarHandle(ref->Name->GetHash()); + + bool force_absolute_load = false; + + // If the variable is from a previous scope, load it from an absolute address. local offsets + // will change depending on where they are called. + if (var_handle->ScopeIndex < mScopeIndex) { + force_absolute_load = true; + } + + if (!var_handle) { + printf("Could not find var handle!"); + return FX_REG_NONE; + } + + FxScriptRegister reg = FindFreeRegister(); + + MARK_REGISTER_USED(reg); + + DoLoad(var_handle->Offset, reg, force_absolute_load); + + if (mode == RhsMode::RHS_FETCH_TO_REGISTER) { + return reg; + } + + // If we are just copying the variable to this new variable, we can free the register after + // we push to the stack. + if (mode == RhsMode::RHS_DEFINE_IN_MEMORY) { + if (var_handle->Type == FxScriptValue::STRING) { + EmitType(var_handle->Type); + } + + EmitPush32r(reg); + MARK_REGISTER_FREE(reg); + + return FX_REG_NONE; + } + + // This is a reference to a variable, return the register we loaded it into + return reg; +} + +void FxScriptIREmitter::DoLoad(uint32 stack_offset, FxScriptRegister output_reg, bool force_absolute) +{ + if (stack_offset < 0xFFFE && !force_absolute) { + // Relative load + + // Calculate the relative index to the current stack offset + int input_offset = -(static_cast(mStackOffset) - static_cast(stack_offset)); + + EmitLoad32(input_offset, output_reg); + } + else { + // Absolute load + EmitLoadAbsolute32(stack_offset, output_reg); + } +} + +void FxScriptIREmitter::DoSaveInt32(uint32 stack_offset, uint32 value, bool force_absolute) +{ + if (stack_offset < 0xFFFE && !force_absolute) { + // Relative save + + // Calculate the relative index to the current stack offset + int input_offset = -(static_cast(mStackOffset) - static_cast(stack_offset)); + + EmitSave32(input_offset, value); + } + else { + // Absolute save + EmitSaveAbsolute32(stack_offset, value); + } +} + +void FxScriptIREmitter::DoSaveReg32(uint32 stack_offset, FxScriptRegister reg, bool force_absolute) +{ + if (stack_offset < 0xFFFE && !force_absolute) { + // Relative save + + // Calculate the relative index to the current stack offset + int input_offset = -(static_cast(mStackOffset) - static_cast(stack_offset)); + + EmitSaveReg32(input_offset, reg); + } + else { + // Absolute save + EmitSaveAbsoluteReg32(stack_offset, reg); + } +} + +void FxScriptIREmitter::EmitAssign(FxAstAssign* assign) +{ + FxScriptBytecodeVarHandle* var_handle = FindVarHandle(assign->Var->Name->GetHash()); + if (var_handle == nullptr) { + printf("!!! Var '%.*s' does not exist!\n", assign->Var->Name->Length, assign->Var->Name->Start); + return; + } + + // bool force_absolute_save = false; + + // if (var_handle->ScopeIndex < mScopeIndex) { + // force_absolute_save = true; + // } + + // int output_offset = -(static_cast(mStackOffset) - static_cast(var_handle->Offset)); + + if (!var_handle) { + printf("Could not find var handle to assign to!"); + return; + } + + EmitRhs(assign->Rhs, RhsMode::RHS_ASSIGN_TO_HANDLE, var_handle); +} + +FxScriptRegister FxScriptIREmitter::EmitLiteralInt(FxAstLiteral* literal, RhsMode mode, FxScriptBytecodeVarHandle* handle) +{ + // If this is on variable definition, push the value to the stack. + if (mode == RhsMode::RHS_DEFINE_IN_MEMORY) { + EmitPush32(literal->Value.ValueInt); + + return FX_REG_NONE; + } + + // If this is as a literal, push the value to the stack and pop onto the target register. + else if (mode == RhsMode::RHS_FETCH_TO_REGISTER) { + // EmitPush32(literal->Value.ValueInt); + + FxScriptRegister output_reg = FindFreeRegister(); + // EmitPop32(output_reg); + + EmitMoveInt32(output_reg, literal->Value.ValueInt); + + // Mark the output register as used to store it + MARK_REGISTER_USED(output_reg); + + return output_reg; + } + + else if (mode == RhsMode::RHS_ASSIGN_TO_HANDLE) { + const bool force_absolute_save = (handle->ScopeIndex < mScopeIndex); + DoSaveInt32(handle->Offset, literal->Value.ValueInt, force_absolute_save); + + return FX_REG_NONE; + } + + return FX_REG_NONE; +} + + +FxScriptRegister FxScriptIREmitter::EmitLiteralString(FxAstLiteral* literal, RhsMode mode, FxScriptBytecodeVarHandle* handle) +{ + const uint32 string_length = strlen(literal->Value.ValueString); + + // Emit the length and string data + const uint32 string_position = EmitDataString(literal->Value.ValueString, string_length); + + // local string some_value = "Some String"; + if (mode == RhsMode::RHS_DEFINE_IN_MEMORY) { + // Push the location and mark it as a pointer to a string + EmitType(FxScriptValue::STRING); + EmitPush32(string_position); + + return FX_REG_NONE; + } + + // some_function("Some String") + else if (mode == RhsMode::RHS_FETCH_TO_REGISTER) { + // Push the location for the string and pop it back to a register. + EmitType(FxScriptValue::STRING); + + // Push the string position + // EmitPush32(string_position); + + // Find a register to output to and write the index + FxScriptRegister output_reg = FindFreeRegister(); + // EmitPop32(output_reg); + + EmitMoveInt32(output_reg, string_position); + + // Mark the output register as used to store it + MARK_REGISTER_USED(output_reg); + + return output_reg; + } + + // some_previous_value = "Some String"; + else if (mode == RhsMode::RHS_ASSIGN_TO_HANDLE) { + const bool force_absolute_save = (handle->ScopeIndex < mScopeIndex); + + DoSaveInt32(handle->Offset, string_position, force_absolute_save); + handle->Type = FxScriptValue::STRING; + + return FX_REG_NONE; + } + + return FX_REG_NONE; +} + +FxScriptRegister FxScriptIREmitter::EmitRhs(FxAstNode* rhs, FxScriptIREmitter::RhsMode mode, FxScriptBytecodeVarHandle* handle) +{ + if (rhs->NodeType == FX_AST_LITERAL) { + FxAstLiteral* literal = reinterpret_cast(rhs); + + if (literal->Value.Type == FxScriptValue::INT) { + return EmitLiteralInt(literal, mode, handle); + } + else if (literal->Value.Type == FxScriptValue::STRING) { + return EmitLiteralString(literal, mode, handle); + } + else if (literal->Value.Type == FxScriptValue::REF) { + // Reference another value, load from memory into register + FxScriptRegister output_register = EmitVarFetch(literal->Value.ValueRef, mode); + if (mode == IRRhsMode::RHS_ASSIGN_TO_HANDLE) { + DoSaveReg32(handle->Offset, output_register); + } + + return output_register; + } + + return FX_REG_NONE; + } + + else if (rhs->NodeType == FX_AST_ACTIONCALL || rhs->NodeType == FX_AST_BINOP) { + FxScriptRegister result_register = FX_REG_XR; + + if (rhs->NodeType == FX_AST_BINOP) { + result_register = EmitBinop(reinterpret_cast(rhs), handle); + } + + else if (rhs->NodeType == FX_AST_ACTIONCALL) { + DoActionCall(reinterpret_cast(rhs)); + // Action results are stored in XR + result_register = FX_REG_XR; + } + + + if (mode == RhsMode::RHS_DEFINE_IN_MEMORY) { + uint32 offset = mStackOffset; + EmitPush32r(result_register); + + if (handle) { + handle->Offset = offset; + } + + return FX_REG_NONE; + } + + else if (mode == RhsMode::RHS_FETCH_TO_REGISTER) { + // Push the result to a register + EmitPush32r(result_register); + + // Find a register to output to, and pop the value to there. + FxScriptRegister output_reg = FindFreeRegister(); + EmitPop32(output_reg); + + // Mark the output register as used to store it + MARK_REGISTER_USED(output_reg); + + return output_reg; + } + else if (mode == RhsMode::RHS_ASSIGN_TO_HANDLE) { + const bool force_absolute_save = (handle->ScopeIndex < mScopeIndex); + + // Save the value back to the variable + DoSaveReg32(handle->Offset, result_register, force_absolute_save); + + return FX_REG_NONE; + } + } + + return FX_REG_NONE; +} + +FxScriptBytecodeVarHandle* FxScriptIREmitter::DoVarDeclare(FxAstVarDecl* decl, VarDeclareMode mode) +{ + RETURN_VALUE_IF_NO_NODE(decl, nullptr); + + const uint16 size_of_type = static_cast(sizeof(int32)); + + const FxHash type_int = FxHashStr("int"); + const FxHash type_string = FxHashStr("string"); + + FxHash decl_hash = decl->Name->GetHash(); + + FxScriptValue::ValueType value_type = FxScriptValue::INT; + + switch (decl_hash) { + case type_int: + value_type = FxScriptValue::INT; + break; + case type_string: + value_type = FxScriptValue::STRING; + break; + }; + + FxScriptBytecodeVarHandle handle { + .HashedName = decl->Name->GetHash(), + .Type = value_type, // Just int for now + .Offset = (mStackOffset), + .SizeOnStack = size_of_type, + .ScopeIndex = mScopeIndex, + }; + + VarHandles.Insert(handle); + + FxScriptBytecodeVarHandle* inserted_handle = &VarHandles[VarHandles.Size() - 1]; + + if (mode == DECLARE_NO_EMIT) { + // Do not emit any values + return inserted_handle; + } + + + if (decl->Assignment) { + FxAstNode* rhs = decl->Assignment->Rhs; + + EmitRhs(rhs, RhsMode::RHS_DEFINE_IN_MEMORY, inserted_handle); + + + // EmitPush32(0); + + // EmitRhs(rhs, RhsMode::RHS_ASSIGN_TO_HANDLE, inserted_handle); + } + else { + // There is no assignment, push zero as the value for now and + // a later assignment can set it using save32. + EmitPush32(0); + } + + return inserted_handle; +} + +void FxScriptIREmitter::DoActionCall(FxAstActionCall* call) +{ + RETURN_IF_NO_NODE(call); + + FxScriptBytecodeActionHandle* handle = FindActionHandle(call->HashedName); + + + std::vector call_locations; + call_locations.reserve(8); + + // Push all params to stack + for (FxAstNode* param : call->Params) { + // FxScriptRegister reg = + if (param->NodeType == FX_AST_ACTIONCALL) { + EmitRhs(param, RhsMode::RHS_DEFINE_IN_MEMORY, nullptr); + call_locations.push_back(mStackOffset - 4); + } + // MARK_REGISTER_FREE(reg); + } + + EmitPush32r(FX_REG_RA); + + EmitParamsStart(); + + int call_location_index = 0; + + // Push all params to stack + for (FxAstNode* param : call->Params) { + if (param->NodeType == FX_AST_ACTIONCALL) { + FxScriptRegister temp_register = FindFreeRegister(); + + DoLoad(call_locations[call_location_index], temp_register); + call_location_index++; + + EmitPush32r(temp_register); + + continue; + } + + EmitRhs(param, RhsMode::RHS_DEFINE_IN_MEMORY, nullptr); + } + + // The handle could not be found, write it as a possible external symbol. + if (!handle) { + printf("Call name-> %u\n", call->HashedName); + + // Since popping the parameters are handled internally in the VM, + // we need to decrement the stack offset here. + for (int i = 0; i < call->Params.size(); i++) { + mStackOffset -= 4; + } + + EmitJumpCallExternal(call->HashedName); + + EmitPop32(FX_REG_RA); + return; + } + + EmitJumpCallAbsolute(handle->BytecodeIndex); + + EmitPop32(FX_REG_RA); +} + +FxScriptBytecodeVarHandle* FxScriptIREmitter::DefineAndFetchParam(FxAstNode* param_decl_node) +{ + if (param_decl_node->NodeType != FX_AST_VARDECL) { + printf("!!! param node type is not vardecl!\n"); + return nullptr; + } + + // Emit variable without emitting pushes or pops + FxScriptBytecodeVarHandle* handle = DoVarDeclare(reinterpret_cast(param_decl_node), DECLARE_NO_EMIT); + + if (!handle) { + printf("!!! could not define and fetch param!\n"); + return nullptr; + } + + assert(handle->SizeOnStack == 4); + + mStackOffset += handle->SizeOnStack; + + return handle; +} + +FxScriptBytecodeVarHandle* FxScriptIREmitter::DefineReturnVar(FxAstVarDecl* decl) +{ + RETURN_VALUE_IF_NO_NODE(decl, nullptr); + + return DoVarDeclare(decl); +} + +void FxScriptIREmitter::EmitAction(FxAstActionDecl* action) +{ + RETURN_IF_NO_NODE(action); + + ++mScopeIndex; + + // Store the bytecode offset before the action is emitted + + const size_t start_of_action = mBytecode.Size(); + printf("Start of action %zu\n", start_of_action); + + // Emit the jump instruction, we will update the jump position after emitting all of the code inside the block + EmitJumpRelative(0); + + // const uint32 initial_stack_offset = mStackOffset; + + const size_t header_jump_start_index = start_of_action + sizeof(uint16); + + size_t start_var_handle_count = VarHandles.Size(); + + // Offset for the pushed return address + mStackOffset += 4; + + // Emit the body of the action + { + for (FxAstNode* param_decl_node : action->Params->Statements) { + DefineAndFetchParam(param_decl_node); + } + + FxScriptBytecodeVarHandle* return_var = DefineReturnVar(action->ReturnVar); + + EmitBlock(action->Block); + + // Check to see if there has been a return statement in the action + bool block_has_return = false; + + for (FxAstNode* statement : action->Block->Statements) { + if (statement->NodeType == FX_AST_RETURN) { + block_has_return = true; + break; + } + } + + // There is no return statement in the action's block, add a return statement + if (!block_has_return) { + EmitJumpReturnToCaller(); + + if (return_var != nullptr) { + DoLoad(return_var->Offset, FX_REG_XR); + } + } + } + + // Return offset back to pre-call + mStackOffset -= 4; + + const size_t end_of_action = mBytecode.Size(); + const uint16 distance_to_action = static_cast(end_of_action - (start_of_action)-4); + + // Update the jump to the end of the action + mBytecode[header_jump_start_index] = static_cast(distance_to_action >> 8); + mBytecode[header_jump_start_index + 1] = static_cast((distance_to_action & 0xFF)); + + FxScriptBytecodeActionHandle action_handle {.HashedName = action->Name->GetHash(), .BytecodeIndex = static_cast(start_of_action + 4)}; + + const size_t number_of_scope_var_handles = VarHandles.Size() - start_var_handle_count; + printf("Number of var handles to remove: %zu\n", number_of_scope_var_handles); + + ActionHandles.push_back(action_handle); + + --mScopeIndex; + + // Delete the variables on the stack + for (int i = 0; i < number_of_scope_var_handles; i++) { + FxScriptBytecodeVarHandle* var = VarHandles.RemoveLast(); + assert(var->SizeOnStack == 4); + mStackOffset -= var->SizeOnStack; + } +} + +void FxScriptIREmitter::EmitBlock(FxAstBlock* block) +{ + RETURN_IF_NO_NODE(block); + + for (FxAstNode* node : block->Statements) { + Emit(node); + } +} + +void FxScriptIREmitter::PrintBytecode() +{ + const size_t size = mBytecode.Size(); + for (int i = 0; i < 25; i++) { + printf("%02d ", i); + } + printf("\n"); + for (int i = 0; i < 25; i++) { + printf("---"); + } + printf("\n"); + + for (size_t i = 0; i < size; i++) { + printf("%02X ", mBytecode[i]); + + if (i > 0 && ((i + 1) % 25) == 0) { + printf("\n"); + } + } + printf("\n"); +} + +#pragma endregion IrEmitter + + +///////////////////////////////////// +// Bytecode Printer +///////////////////////////////////// + +uint16 FxScriptIRPrinter::Read16() +{ + uint8 lo = mBytecode[mBytecodeIndex++]; + uint8 hi = mBytecode[mBytecodeIndex++]; + + return ((static_cast(lo) << 8) | hi); +} + +uint32 FxScriptIRPrinter::Read32() +{ + uint16 lo = Read16(); + uint16 hi = Read16(); + + return ((static_cast(lo) << 16) | hi); +} + +#define BC_PRINT_OP(fmt_, ...) snprintf(s, 128, fmt_, ##__VA_ARGS__) + +void FxScriptIRPrinter::DoLoad(char* s, uint8 op_base, uint8 op_spec_raw) +{ + uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); + uint8 op_reg = (op_spec_raw & 0x0F); + + if (op_spec == IrSpecLoad_Int32) { + int16 offset = Read16(); + BC_PRINT_OP("load32 %d, %s", offset, FxScriptIREmitter::GetRegisterName(static_cast(op_reg))); + } + else if (op_spec == IrSpecLoad_AbsoluteInt32) { + uint32 offset = Read32(); + BC_PRINT_OP("load32a %u, %s", offset, FxScriptIREmitter::GetRegisterName(static_cast(op_reg))); + } +} + +void FxScriptIRPrinter::DoPush(char* s, uint8 op_base, uint8 op_spec) +{ + if (op_spec == IrSpecPush_Int32) { + uint32 value = Read32(); + BC_PRINT_OP("push32 %u", value); + } + else if (op_spec == IrSpecPush_Reg32) { + uint16 reg = Read16(); + BC_PRINT_OP("push32r %s", FxScriptIREmitter::GetRegisterName(static_cast(reg))); + } +} + +void FxScriptIRPrinter::DoPop(char* s, uint8 op_base, uint8 op_spec_raw) +{ + uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); + uint8 op_reg = (op_spec_raw & 0x0F); + + if (op_spec == IrSpecPush_Int32) { + BC_PRINT_OP("pop32 %s", FxScriptIREmitter::GetRegisterName(static_cast(op_reg))); + } +} + +void FxScriptIRPrinter::DoArith(char* s, uint8 op_base, uint8 op_spec) +{ + uint8 a_reg = mBytecode[mBytecodeIndex++]; + uint8 b_reg = mBytecode[mBytecodeIndex++]; + + if (op_spec == IrSpecArith_Add) { + BC_PRINT_OP("add32 %s, %s", FxScriptIREmitter::GetRegisterName(static_cast(a_reg)), + FxScriptIREmitter::GetRegisterName(static_cast(b_reg))); + } +} + +void FxScriptIRPrinter::DoSave(char* s, uint8 op_base, uint8 op_spec) +{ + // Save a imm32 into an offset in the stack + if (op_spec == IrSpecSave_Int32) { + const int16 offset = Read16(); + const uint32 value = Read32(); + + BC_PRINT_OP("save32 %d, %u", offset, value); + } + + // Save a register into an offset in the stack + else if (op_spec == IrSpecSave_Reg32) { + const int16 offset = Read16(); + uint16 reg = Read16(); + + BC_PRINT_OP("save32r %d, %s", offset, FxScriptIREmitter::GetRegisterName(static_cast(reg))); + } + else if (op_spec == IrSpecSave_AbsoluteInt32) { + const uint32 offset = Read32(); + const uint32 value = Read32(); + + BC_PRINT_OP("save32a %u, %u", offset, value); + } + else if (op_spec == IrSpecSave_AbsoluteReg32) { + const uint32 offset = Read32(); + uint16 reg = Read16(); + + BC_PRINT_OP("save32ar %u, %s", offset, FxScriptIREmitter::GetRegisterName(static_cast(reg))); + } +} + +void FxScriptIRPrinter::DoJump(char* s, uint8 op_base, uint8 op_spec) +{ + if (op_spec == IrSpecJump_Relative) { + uint16 offset = Read16(); + printf("# jump relative to (%u)\n", mBytecodeIndex + offset); + BC_PRINT_OP("jmpr %d", offset); + } + else if (op_spec == IrSpecJump_Absolute) { + uint32 position = Read32(); + BC_PRINT_OP("jmpa %u", position); + } + else if (op_spec == IrSpecJump_AbsoluteReg32) { + uint16 reg = Read16(); + BC_PRINT_OP("jmpar %s", FxScriptIREmitter::GetRegisterName(static_cast(reg))); + } + else if (op_spec == IrSpecJump_CallAbsolute) { + uint32 position = Read32(); + BC_PRINT_OP("calla %u", position); + } + else if (op_spec == IrSpecJump_ReturnToCaller) { + BC_PRINT_OP("ret"); + } + else if (op_spec == IrSpecJump_CallExternal) { + uint32 hashed_name = Read32(); + BC_PRINT_OP("callext %u", hashed_name); + } +} + +void FxScriptIRPrinter::DoData(char* s, uint8 op_base, uint8 op_spec) +{ + if (op_spec == IrSpecData_String) { + uint16 length = Read16(); + char* data_str = FX_SCRIPT_ALLOC_MEMORY(char, length); + uint16* data_str16 = reinterpret_cast(data_str); + + uint32 bytecode_end = mBytecodeIndex + length; + int data_index = 0; + while (mBytecodeIndex < bytecode_end) { + uint16 value16 = Read16(); + data_str16[data_index++] = ((value16 << 8) | (value16 >> 8)); + } + + BC_PRINT_OP("datastr %d, %.*s", length, length, data_str); + + FX_SCRIPT_FREE(char, data_str); + } + else if (op_spec == IrSpecData_ParamsStart) { + BC_PRINT_OP("paramsstart"); + } +} + +void FxScriptIRPrinter::DoType(char* s, uint8 op_base, uint8 op_spec) +{ + if (op_spec == IrSpecType_Int) { + BC_PRINT_OP("typeint"); + } + else if (op_spec == IrSpecType_String) { + BC_PRINT_OP("typestr"); + } +} + +void FxScriptIRPrinter::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) +{ + uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); + uint8 op_reg = (op_spec_raw & 0x0F); + + if (op_spec == IrSpecMove_Int32) { + uint32 value = Read32(); + BC_PRINT_OP("move32 %s, %u\t", FxScriptIREmitter::GetRegisterName(static_cast(op_reg)), value); + } +} + + +void FxScriptIRPrinter::Print() +{ + while (mBytecodeIndex < mBytecode.Size()) { + PrintOp(); + } +} + +void FxScriptIRPrinter::PrintOp() +{ + uint32 bc_index = mBytecodeIndex; + + uint16 op_full = Read16(); + + const uint8 op_base = static_cast(op_full >> 8); + const uint8 op_spec = static_cast(op_full & 0xFF); + + char s[128]; + + switch (op_base) { + case IrBase_Push: + DoPush(s, op_base, op_spec); + break; + case IrBase_Pop: + DoPop(s, op_base, op_spec); + break; + case IrBase_Load: + DoLoad(s, op_base, op_spec); + break; + case IrBase_Arith: + DoArith(s, op_base, op_spec); + break; + case IrBase_Jump: + DoJump(s, op_base, op_spec); + break; + case IrBase_Save: + DoSave(s, op_base, op_spec); + break; + case IrBase_Data: + DoData(s, op_base, op_spec); + break; + case IrBase_Type: + DoType(s, op_base, op_spec); + break; + case IrBase_Move: + DoMove(s, op_base, op_spec); + break; + } + + printf("%-25s", s); + + printf("\t# Offset: %u\n", bc_index); } diff --git a/FxScript.hpp b/FxScript.hpp index 8e1c216..dcd3d86 100644 --- a/FxScript.hpp +++ b/FxScript.hpp @@ -1,10 +1,10 @@ #pragma once -#include - #include "FxMPPagedArray.hpp" #include "FxTokenizer.hpp" +#include + #define FX_SCRIPT_VERSION_MAJOR 0 #define FX_SCRIPT_VERSION_MINOR 3 #define FX_SCRIPT_VERSION_PATCH 1 @@ -46,13 +46,11 @@ struct FxScriptValue { } - explicit FxScriptValue(ValueType type, int value) - : Type(type), ValueInt(value) + explicit FxScriptValue(ValueType type, int value) : Type(type), ValueInt(value) { } - explicit FxScriptValue(ValueType type, float value) - : Type(type), ValueFloat(value) + explicit FxScriptValue(ValueType type, float value) : Type(type), ValueFloat(value) { } @@ -107,7 +105,7 @@ struct FxScriptValue enum FxAstType { FX_AST_LITERAL, - //FX_AST_NAME, + // FX_AST_NAME, FX_AST_BINOP, FX_AST_UNARYOP, @@ -141,7 +139,7 @@ struct FxAstLiteral : public FxAstNode this->NodeType = FX_AST_LITERAL; } - //FxTokenizer::Token* Token = nullptr; + // FxTokenizer::Token* Token = nullptr; FxScriptValue Value; }; @@ -186,7 +184,7 @@ struct FxAstAssign : public FxAstNode } FxAstVarRef* Var = nullptr; - //FxScriptValue Value; + // FxScriptValue Value; FxAstNode* Rhs = nullptr; }; @@ -249,7 +247,7 @@ struct FxAstActionCall : public FxAstNode FxScriptAction* Action = nullptr; FxHash HashedName = 0; - std::vector Params{}; // FxAstLiteral or FxAstVarRef + std::vector Params {}; // FxAstLiteral or FxAstVarRef }; struct FxAstReturn : public FxAstNode @@ -303,8 +301,7 @@ struct FxScriptVar : public FxScriptLabelledData { } - FxScriptVar(FxTokenizer::Token* type, FxTokenizer::Token* name, FxScriptScope* scope, bool is_external = false) - : Type(type) + FxScriptVar(FxTokenizer::Token* type, FxTokenizer::Token* name, FxScriptScope* scope, bool is_external = false) : Type(type) { this->HashedName = name->GetHash(); this->Name = name; @@ -321,7 +318,7 @@ struct FxScriptVar : public FxScriptLabelledData IsExternal = other.IsExternal; } - FxScriptVar& operator = (FxScriptVar&& other) noexcept + FxScriptVar& operator=(FxScriptVar&& other) noexcept { HashedName = other.HashedName; Type = other.Type; @@ -353,13 +350,12 @@ struct FxScriptVar : public FxScriptLabelledData } }; -class FxScriptInterpreter; class FxScriptVM; struct FxScriptExternalFunc { - //using FuncType = void (*)(FxScriptInterpreter& interpreter, std::vector& params, FxScriptValue* return_value); + // using FuncType = void (*)(FxScriptInterpreter& interpreter, std::vector& params, FxScriptValue* return_value); using FuncType = void (*)(FxScriptVM* vm, std::vector& params, FxScriptValue* return_value); @@ -399,7 +395,8 @@ struct FxScriptScope return FindInScope(hashed_name, Actions); } - template requires std::is_base_of_v + template + requires std::is_base_of_v T* FindInScope(FxHash hashed_name, const FxMPPagedArray& buffer) { for (T& var : buffer) { @@ -412,7 +409,7 @@ struct FxScriptScope } }; -class FxScriptInterpreter; +// class FxScriptInterpreter; class FxConfigScript { @@ -471,17 +468,19 @@ class FxConfigScript * @param command The command to execute on the script. * @return If the command has been executed */ - bool ExecuteUserCommand(const char* command, FxScriptInterpreter& interpreter); + // bool ExecuteUserCommand(const char* command, FxScriptInterpreter& interpreter); Token& GetToken(int offset = 0); Token& EatToken(TT token_type); - void RegisterExternalFunc(FxHash func_name, std::vector param_types, FxScriptExternalFunc::FuncType func, bool is_variadic); + void RegisterExternalFunc(FxHash func_name, std::vector param_types, FxScriptExternalFunc::FuncType func, + bool is_variadic); void DefineExternalVar(const char* type, const char* name, const FxScriptValue& value); private: - template requires std::is_base_of_v + template + requires std::is_base_of_v T* FindLabelledData(FxHash hashed_name, FxMPPagedArray& buffer) { FxScriptScope* scope = mCurrentScope; @@ -522,7 +521,6 @@ class FxConfigScript // Name tokens for internal variables Token* mTokenReturnVar = nullptr; - }; ////////////////////////////////// @@ -533,7 +531,7 @@ class FxAstPrinter { public: FxAstPrinter(FxAstBlock* root_block) - //: mRootBlock(root_block) + //: mRootBlock(root_block) { } @@ -624,11 +622,11 @@ class FxAstPrinter else { puts("[UNKNOWN]"); } - //else if (node->NodeType == FX_AST_) + // else if (node->NodeType == FX_AST_) } public: - //FxAstBlock* mRootBlock = nullptr; + // FxAstBlock* mRootBlock = nullptr; }; ///////////////////////////////////////////// @@ -672,12 +670,12 @@ enum FxScriptRegisterFlag : uint16 FX_REGFLAG_XR = 0x20, }; -inline FxScriptRegisterFlag operator | (FxScriptRegisterFlag a, FxScriptRegisterFlag b) +inline FxScriptRegisterFlag operator|(FxScriptRegisterFlag a, FxScriptRegisterFlag b) { return static_cast(static_cast(a) | static_cast(b)); } -inline FxScriptRegisterFlag operator & (FxScriptRegisterFlag a, FxScriptRegisterFlag b) +inline FxScriptRegisterFlag operator&(FxScriptRegisterFlag a, FxScriptRegisterFlag b) { return static_cast(static_cast(a) & static_cast(b)); } @@ -723,9 +721,10 @@ class FxScriptBCEmitter static const char* GetRegisterName(FxScriptRegister reg); - FxMPPagedArray mBytecode{}; + FxMPPagedArray mBytecode {}; - enum VarDeclareMode { + enum VarDeclareMode + { DECLARE_DEFAULT, DECLARE_NO_EMIT, }; @@ -797,11 +796,10 @@ class FxScriptBCEmitter void MarkRegisterFree(FxScriptRegister reg); public: - FxMPPagedArray VarHandles; std::vector ActionHandles; -private: +private: FxScriptRegisterFlag mRegsInUse = FX_REGFLAG_NONE; int64 mStackOffset = 0; @@ -863,7 +861,7 @@ class FxScriptVM mPushedTypes.Create(64); Stack = FX_SCRIPT_ALLOC_MEMORY(uint8, 1024); - //mStackOffset = 0; + // mStackOffset = 0; Registers[FX_REG_SP] = 0; memset(Registers, 0, sizeof(Registers)); @@ -931,7 +929,7 @@ class FxScriptVM //////////////////////////////////////////////// // Script Interpreter //////////////////////////////////////////////// - +#if 0 class FxScriptInterpreter { public: @@ -981,7 +979,7 @@ class FxScriptInterpreter FxScriptScope* mCurrentScope = nullptr; }; - +#endif ///////////////////////////////////// // Bytecode to x86 Transpiler ///////////////////////////////////// @@ -1027,3 +1025,154 @@ class FxScriptTranspilerX86 FxMPPagedArray mBytecode; }; + + +//////////////////////////////////////////// +// IR Emitter +//////////////////////////////////////////// + + +class FxScriptIREmitter +{ +public: + FxScriptIREmitter() = default; + + void BeginEmitting(FxAstNode* node); + void Emit(FxAstNode* node); + + enum RhsMode + { + RHS_FETCH_TO_REGISTER, + + /** + * @brief Pushes the value to the stack, assuming that the value does not exist yet. + */ + RHS_DEFINE_IN_MEMORY, + + RHS_ASSIGN_TO_HANDLE, + }; + + static FxScriptRegister RegFlagToReg(FxScriptRegisterFlag reg_flag); + static FxScriptRegisterFlag RegToRegFlag(FxScriptRegister reg); + + static const char* GetRegisterName(FxScriptRegister reg); + + FxMPPagedArray mBytecode {}; + + enum VarDeclareMode + { + DECLARE_DEFAULT, + DECLARE_NO_EMIT, + }; + + +private: + void EmitBlock(FxAstBlock* block); + void EmitAction(FxAstActionDecl* action); + void DoActionCall(FxAstActionCall* call); + FxScriptBytecodeVarHandle* DoVarDeclare(FxAstVarDecl* decl, VarDeclareMode mode = DECLARE_DEFAULT); + void EmitAssign(FxAstAssign* assign); + FxScriptBytecodeVarHandle* DefineAndFetchParam(FxAstNode* param_decl_node); + FxScriptBytecodeVarHandle* DefineReturnVar(FxAstVarDecl* decl); + + FxScriptRegister EmitVarFetch(FxAstVarRef* ref, RhsMode mode); + + void DoLoad(uint32 stack_offset, FxScriptRegister output_reg, bool force_absolute = false); + void DoSaveInt32(uint32 stack_offset, uint32 value, bool force_absolute = false); + void DoSaveReg32(uint32 stack_offset, FxScriptRegister reg, bool force_absolute = false); + + void EmitPush32(uint32 value); + void EmitPush32r(FxScriptRegister reg); + + void EmitPop32(FxScriptRegister output_reg); + + void EmitLoad32(int offset, FxScriptRegister output_reg); + void EmitLoadAbsolute32(uint32 position, FxScriptRegister output_reg); + + void EmitSave32(int16 offset, uint32 value); + void EmitSaveReg32(int16 offset, FxScriptRegister reg); + + void EmitSaveAbsolute32(uint32 offset, uint32 value); + void EmitSaveAbsoluteReg32(uint32 offset, FxScriptRegister reg); + + void EmitJumpRelative(uint16 offset); + void EmitJumpAbsolute(uint32 position); + void EmitJumpAbsoluteReg32(FxScriptRegister reg); + void EmitJumpCallAbsolute(uint32 position); + void EmitJumpReturnToCaller(); + void EmitJumpCallExternal(FxHash hashed_name); + + void EmitMoveInt32(FxScriptRegister reg, uint32 value); + + void EmitParamsStart(); + void EmitType(FxScriptValue::ValueType type); + + uint32 EmitDataString(char* str, uint16 length); + + FxScriptRegister EmitBinop(FxAstBinop* binop, FxScriptBytecodeVarHandle* handle); + + FxScriptRegister EmitRhs(FxAstNode* rhs, RhsMode mode, FxScriptBytecodeVarHandle* handle); + + FxScriptRegister EmitLiteralInt(FxAstLiteral* literal, RhsMode mode, FxScriptBytecodeVarHandle* handle); + FxScriptRegister EmitLiteralString(FxAstLiteral* literal, RhsMode mode, FxScriptBytecodeVarHandle* handle); + + + void WriteOp(uint8 base_op, uint8 spec_op); + void Write16(uint16 value); + void Write32(uint32 value); + + FxScriptRegister FindFreeRegister(); + + FxScriptBytecodeVarHandle* FindVarHandle(FxHash hashed_name); + FxScriptBytecodeActionHandle* FindActionHandle(FxHash hashed_name); + + void PrintBytecode(); + + void MarkRegisterUsed(FxScriptRegister reg); + void MarkRegisterFree(FxScriptRegister reg); + +public: + FxMPPagedArray VarHandles; + std::vector ActionHandles; + +private: + FxScriptRegisterFlag mRegsInUse = FX_REGFLAG_NONE; + + int64 mStackOffset = 0; + uint32 mStackSize = 0; + + uint16 mScopeIndex = 0; +}; + + +class FxScriptIRPrinter +{ +public: + FxScriptIRPrinter(FxMPPagedArray& bytecode) + { + mBytecode = bytecode; + mBytecode.DoNotDestroy = true; + } + + void Print(); + void PrintOp(); + + +private: + uint16 Read16(); + uint32 Read32(); + + void DoPush(char* s, uint8 op_base, uint8 op_spec); + void DoPop(char* s, uint8 op_base, uint8 op_spec); + void DoLoad(char* s, uint8 op_base, uint8 op_spec); + void DoArith(char* s, uint8 op_base, uint8 op_spec); + void DoSave(char* s, uint8 op_base, uint8 op_spec); + void DoJump(char* s, uint8 op_base, uint8 op_spec); + void DoData(char* s, uint8 op_base, uint8 op_spec); + void DoType(char* s, uint8 op_base, uint8 op_spec); + void DoMove(char* s, uint8 op_base, uint8 op_spec); + +private: + uint32 mBytecodeIndex = 0; + FxMPPagedArray mBytecode; +}; diff --git a/FxScriptBytecode.hpp b/FxScriptBytecode.hpp index f96df0b..99b04f0 100644 --- a/FxScriptBytecode.hpp +++ b/FxScriptBytecode.hpp @@ -22,24 +22,24 @@ enum OpBase : uint8 enum OpSpecPush : uint8 { - OpSpecPush_Int32 = 1, // PUSH32 [imm] - OpSpecPush_Reg32, // PUSH32r [%r32] + OpSpecPush_Int32 = 1, // PUSH32 [imm] + OpSpecPush_Reg32, // PUSH32r [%r32] }; enum OpSpecPop : uint8 { - OpSpecPop_Int32 = 1, // POP32 [%r32] + OpSpecPop_Int32 = 1, // POP32 [%r32] }; enum OpSpecLoad : uint8 { - OpSpecLoad_Int32 = 1, // LOAD32 [offset] [%r32] + OpSpecLoad_Int32 = 1, // LOAD32 [offset] [%r32] OpSpecLoad_AbsoluteInt32, }; enum OpSpecArith : uint8 { - OpSpecArith_Add = 1 // ADD [%r32] [%r32] + OpSpecArith_Add = 1 // ADD [%r32] [%r32] }; enum OpSpecSave : uint8 @@ -78,3 +78,81 @@ enum OpSpecMove : uint8 { OpSpecMove_Int32 = 1, }; + + +///////////////////////////////////////////// +// IR Bytecode +///////////////////////////////////////////// + + +enum IrBase : uint8 +{ + IrBase_Push = 1, + IrBase_Pop, + IrBase_Load, + IrBase_Arith, + IrBase_Save, + IrBase_Jump, + IrBase_Data, + IrBase_Type, + IrBase_Move, +}; + +enum IrSpecPush : uint8 +{ + IrSpecPush_Int32 = 1, // PUSH32 [imm] + IrSpecPush_Reg32, // PUSH32r [%r32] +}; + +enum IrSpecPop : uint8 +{ + IrSpecPop_Int32 = 1, // PIr32 [%r32] +}; + +enum IrSpecLoad : uint8 +{ + IrSpecLoad_Int32 = 1, // LOAD32 [offset] [%r32] + IrSpecLoad_AbsoluteInt32, +}; + +enum IrSpecArith : uint8 +{ + IrSpecArith_Add = 1 // ADD [%r32] [%r32] +}; + +enum IrSpecSave : uint8 +{ + IrSpecSave_Int32 = 1, + IrSpecSave_Reg32, + IrSpecSave_AbsoluteInt32, + IrSpecSave_AbsoluteReg32 +}; + +enum IrSpecJump : uint8 +{ + IrSpecJump_Relative = 1, + IrSpecJump_Absolute, + IrSpecJump_AbsoluteReg32, + + IrSpecJump_CallAbsolute, + IrSpecJump_ReturnToCaller, + + IrSpecJump_CallExternal, +}; + +enum IrSpecData : uint8 +{ + IrSpecData_String = 1, + IrSpecData_ParamsStart, +}; + +enum IrSpecType : uint8 +{ + IrSpecType_Int = 1, + IrSpecType_String, +}; + +enum IrSpecMove : uint8 +{ + IrSpecMove_Int32 = 1, +}; From 731c791904bf2f263295815368983da5bbe03505 Mon Sep 17 00:00:00 2001 From: Ethan MacDonald Date: Sun, 24 Aug 2025 14:04:09 -0300 Subject: [PATCH 2/9] Updated and added new IR instructions, renamed to Fox from fxscript --- .clang-tidy | 4 +- FxMPPagedArray.hpp => FoxMPPagedArray.hpp | 41 +- FxScript.cpp => FoxScript.cpp | 1412 +++++++++-------- FoxScript.hpp | 1212 ++++++++++++++ FxScriptBytecode.hpp => FoxScriptBytecode.hpp | 25 +- FxScriptUtil.hpp => FoxScriptUtil.hpp | 31 +- FxTokenizer.hpp => FoxTokenizer.hpp | 79 +- FxScript.hpp | 1178 -------------- Main.cpp | 10 +- Main.fxS => Main.fox | 5 - Makefile | 2 +- 11 files changed, 2079 insertions(+), 1920 deletions(-) rename FxMPPagedArray.hpp => FoxMPPagedArray.hpp (87%) rename FxScript.cpp => FoxScript.cpp (65%) create mode 100644 FoxScript.hpp rename FxScriptBytecode.hpp => FoxScriptBytecode.hpp (86%) rename FxScriptUtil.hpp => FoxScriptUtil.hpp (74%) rename FxTokenizer.hpp => FoxTokenizer.hpp (91%) delete mode 100644 FxScript.hpp rename Main.fxS => Main.fox (98%) diff --git a/.clang-tidy b/.clang-tidy index 70951d1..4000d67 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -56,11 +56,11 @@ CheckOptions: - key: readability-identifier-naming.ClassCase value: CamelCase - key: readability-identifier-naming.ClassPrefix - value: 'Fx' + value: 'Fox' - key: readability-identifier-naming.StructCase value: CamelCase - key: readability-identifier-naming.StructPrefix - value: 'Fx' + value: 'Fox' - key: readability-identifier-naming.FunctionCase value: CamelCase - key: readability-identifier-naming.MethodCase diff --git a/FxMPPagedArray.hpp b/FoxMPPagedArray.hpp similarity index 87% rename from FxMPPagedArray.hpp rename to FoxMPPagedArray.hpp index 7b1d6cd..324bcb0 100644 --- a/FxMPPagedArray.hpp +++ b/FoxMPPagedArray.hpp @@ -1,12 +1,12 @@ #pragma once -#include "FxScriptUtil.hpp" +#include "FoxScriptUtil.hpp" -#include #include +#include template -class FxMPPagedArray +class FoxMPPagedArray { public: struct Page @@ -28,14 +28,12 @@ class FxMPPagedArray // { // } - Iterator(Page* current_page, uint32 index) - : mCurrentPage(current_page), mCurrentIndex(index) + Iterator(Page* current_page, uint32 index) : mCurrentPage(current_page), mCurrentIndex(index) { } - Iterator& operator ++ () + Iterator& operator++() { - ++mCurrentIndex; if (mCurrentIndex > mCurrentPage->Size) { @@ -46,7 +44,7 @@ class FxMPPagedArray return *this; } - Iterator operator ++ (int) + Iterator operator++(int) { Iterator iterator = *this; ++*this; @@ -54,9 +52,8 @@ class FxMPPagedArray return iterator; } - Iterator& operator -- () + Iterator& operator--() { - if (mCurrentIndex == 0) { mCurrentPage = mCurrentPage->Prev; mCurrentIndex = mCurrentPage->Size; @@ -67,12 +64,12 @@ class FxMPPagedArray return *this; } - ElementType& operator * () + ElementType& operator*() { return mCurrentPage->Data[mCurrentIndex]; } - bool operator != (const Iterator& other) + bool operator!=(const Iterator& other) { return mCurrentPage && (mCurrentPage != other.mCurrentPage || mCurrentIndex != other.mCurrentIndex); } @@ -81,14 +78,14 @@ class FxMPPagedArray uint32 mCurrentIndex = 0; }; - FxMPPagedArray() = default; + FoxMPPagedArray() = default; - FxMPPagedArray(uint32 page_node_capacity) + FoxMPPagedArray(uint32 page_node_capacity) { Create(page_node_capacity); } - FxMPPagedArray& operator = (const FxMPPagedArray& other) + FoxMPPagedArray& operator=(const FoxMPPagedArray& other) { FirstPage = other.FirstPage; CurrentPage = other.CurrentPage; @@ -101,7 +98,7 @@ class FxMPPagedArray return *this; } - FxMPPagedArray& operator = (FxMPPagedArray&& other) + FoxMPPagedArray& operator=(FoxMPPagedArray&& other) { FirstPage = other.FirstPage; CurrentPage = other.CurrentPage; @@ -149,7 +146,7 @@ class FxMPPagedArray inline size_t Size() const { - //return GetCalculatedSize(); + // return GetCalculatedSize(); return TrackedSize; } @@ -318,7 +315,7 @@ class FxMPPagedArray } - ElementType& operator [] (size_t index) + ElementType& operator[](size_t index) { return Get(index); } @@ -381,7 +378,7 @@ class FxMPPagedArray CurrentPage = nullptr; } - ~FxMPPagedArray() + ~FoxMPPagedArray() { if (FirstPage == nullptr) { return; @@ -396,7 +393,7 @@ class FxMPPagedArray // Allocate and initialize the page object void* allocated_page = std::malloc(sizeof(Page)); if (allocated_page == nullptr) { - FxPanic("FxPagedArray", "Memory error allocating page", 0); + FoxPanic("FoxPagedArray", "Memory error allocating page", 0); return nullptr; // for msvc } @@ -410,7 +407,7 @@ class FxMPPagedArray void* allocated_nodes = FX_SCRIPT_ALLOC_MEMORY(ElementType, (sizeof(ElementType) * PageNodeCapacity)); if (allocated_nodes == nullptr) { - FxPanic("FxPagedArray", "Memory error allocating page data", 0); + FoxPanic("FoxPagedArray", "Memory error allocating page data", 0); return nullptr; // for msvc } @@ -424,7 +421,7 @@ class FxMPPagedArray inline void SizeCheck(uint32 size) const { if (size > PageNodeCapacity) { - FxPanic("FxPagedArray", "The current size of a page is greater than the allocated page node capacity!", 0); + FoxPanic("FoxPagedArray", "The current size of a page is greater than the allocated page node capacity!", 0); } } diff --git a/FxScript.cpp b/FoxScript.cpp similarity index 65% rename from FxScript.cpp rename to FoxScript.cpp index 2a3e7a0..0735f66 100644 --- a/FxScript.cpp +++ b/FoxScript.cpp @@ -1,6 +1,6 @@ -#include "FxScript.hpp" +#include "FoxScript.hpp" -#include "FxScriptUtil.hpp" +#include "FoxScriptUtil.hpp" #include @@ -12,14 +12,14 @@ #define FX_SCRIPT_SCOPE_GLOBAL_ACTIONS_START_SIZE 32 #define FX_SCRIPT_SCOPE_LOCAL_ACTIONS_START_SIZE 32 -using Token = FxTokenizer::Token; -using TT = FxTokenizer::TokenType; +using Token = FoxTokenizer::Token; +using TT = FoxTokenizer::TokenType; -FxScriptValue FxScriptValue::None {}; +FoxValue FoxValue::None {}; -void FxConfigScript::LoadFile(const char* path) +void FoxConfigScript::LoadFile(const char* path) { - FILE* fp = FxUtil::FileOpen(path, "rb"); + FILE* fp = FoxUtil::FileOpen(path, "rb"); if (fp == nullptr) { printf("[ERROR] Could not open config file at '%s'\n", path); return; @@ -36,7 +36,7 @@ void FxConfigScript::LoadFile(const char* path) printf("[WARNING] Error reading all data from config file at '%s' (read=%zu, size=%zu)\n", path, read_size, file_size); } - FxTokenizer tokenizer(mFileData, read_size); + FoxTokenizer tokenizer(mFileData, read_size); tokenizer.Tokenize(); @@ -51,12 +51,12 @@ void FxConfigScript::LoadFile(const char* path) mScopes.Create(8); mCurrentScope = mScopes.Insert(); mCurrentScope->Vars.Create(FX_SCRIPT_SCOPE_GLOBAL_VARS_START_SIZE); - mCurrentScope->Actions.Create(FX_SCRIPT_SCOPE_GLOBAL_ACTIONS_START_SIZE); + mCurrentScope->Functions.Create(FX_SCRIPT_SCOPE_GLOBAL_ACTIONS_START_SIZE); CreateInternalVariableTokens(); } -Token& FxConfigScript::GetToken(int offset) +Token& FoxConfigScript::GetToken(int offset) { const uint32 idx = mTokenIndex + offset; if (idx < 0 || idx >= mTokens.Size()) { @@ -66,19 +66,19 @@ Token& FxConfigScript::GetToken(int offset) return mTokens[idx]; } -Token& FxConfigScript::EatToken(TT token_type) +Token& FoxConfigScript::EatToken(TT token_type) { Token& token = GetToken(); if (token.Type != token_type) { - printf("[ERROR] %u:%u: Unexpected token type %s when expecting %s!\n", token.FileLine, token.FileColumn, FxTokenizer::GetTypeName(token.Type), - FxTokenizer::GetTypeName(token_type)); + printf("[ERROR] %u:%u: Unexpected token type %s when expecting %s!\n", token.FileLine, token.FileColumn, + FoxTokenizer::GetTypeName(token.Type), FoxTokenizer::GetTypeName(token_type)); mHasErrors = true; } ++mTokenIndex; return token; } -Token* FxConfigScript::CreateTokenFromString(FxTokenizer::TokenType type, const char* text) +Token* FoxConfigScript::CreateTokenFromString(FoxTokenizer::TokenType type, const char* text) { const uint32 name_len = strlen(text); @@ -95,12 +95,12 @@ Token* FxConfigScript::CreateTokenFromString(FxTokenizer::TokenType type, const return token; } -void FxConfigScript::CreateInternalVariableTokens() +void FoxConfigScript::CreateInternalVariableTokens() { mTokenReturnVar = CreateTokenFromString(TT::Identifier, FX_SCRIPT_VAR_RETURN_VAL); } -void PrintDocCommentExample(FxTokenizer::Token* comment, int example_tag_length, bool is_command_mode) +void PrintDocCommentExample(FoxTokenizer::Token* comment, int example_tag_length, bool is_command_mode) { char* start = comment->Start + example_tag_length; @@ -128,7 +128,7 @@ void PrintDocCommentExample(FxTokenizer::Token* comment, int example_tag_length, puts(""); } -void PrintDocComment(FxTokenizer::Token* comment, bool is_command_mode) +void PrintDocComment(FoxTokenizer::Token* comment, bool is_command_mode) { const char* example_tag = "EX: "; const int example_tag_length = 4; @@ -148,34 +148,34 @@ void PrintDocComment(FxTokenizer::Token* comment, bool is_command_mode) printf("%.*s\n", comment->Length, start); } -FxAstNode* FxConfigScript::TryParseKeyword(FxAstBlock* parent_block) +FoxAstNode* FoxConfigScript::TryParseKeyword(FoxAstBlock* parent_block) { if (mTokenIndex >= mTokens.Size()) { return nullptr; } Token& tk = GetToken(); - FxHash hash = tk.GetHash(); + FoxHash hash = tk.GetHash(); - // action [name] ( < [arg type] [arg name] ...> ) { } - constexpr FxHash kw_action = FxHashStr("fn"); + // function [name] ( < [arg type] [arg name] ...> ) { } + constexpr FoxHash kw_function = FoxHashStr("fn"); // local [type] [name] ; - constexpr FxHash kw_local = FxHashStr("local"); + constexpr FoxHash kw_local = FoxHashStr("local"); // global [type] [name] ; - constexpr FxHash kw_global = FxHashStr("global"); + constexpr FoxHash kw_global = FoxHashStr("global"); // return ; - constexpr FxHash kw_return = FxHashStr("return"); + constexpr FoxHash kw_return = FoxHashStr("return"); - // help [name of action] ; - constexpr FxHash kw_help = FxHashStr("help"); + // help [name of function] ; + constexpr FoxHash kw_help = FoxHashStr("help"); - if (hash == kw_action) { + if (hash == kw_function) { EatToken(TT::Identifier); - // ParseActionDeclare(); - return ParseActionDeclare(); + // ParseFunctionDeclare(); + return ParseFunctionDeclare(); } if (hash == kw_local) { EatToken(TT::Identifier); @@ -190,33 +190,33 @@ FxAstNode* FxConfigScript::TryParseKeyword(FxAstBlock* parent_block) if (GetToken().Type != TT::Semicolon) { // There is a value that follows, get the value - FxAstNode* rhs = ParseRhs(); + FoxAstNode* rhs = ParseRhs(); // Assign the return value to __ReturnVal__ - FxAstVarRef* var_ref = FX_SCRIPT_ALLOC_NODE(FxAstVarRef); + FoxAstVarRef* var_ref = FX_SCRIPT_ALLOC_NODE(FoxAstVarRef); var_ref->Name = mTokenReturnVar; - FxAstAssign* assign = FX_SCRIPT_ALLOC_NODE(FxAstAssign); + FoxAstAssign* assign = FX_SCRIPT_ALLOC_NODE(FoxAstAssign); assign->Var = var_ref; assign->Rhs = rhs; parent_block->Statements.push_back(assign); } - FxAstReturn* ret = FX_SCRIPT_ALLOC_NODE(FxAstReturn); + FoxAstReturn* ret = FX_SCRIPT_ALLOC_NODE(FoxAstReturn); return ret; } if (hash == kw_help) { EatToken(TT::Identifier); - FxTokenizer::Token& func_ref = EatToken(TT::Identifier); + FoxTokenizer::Token& func_ref = EatToken(TT::Identifier); - FxScriptAction* action = FindAction(func_ref.GetHash()); + FoxFunction* function = FindFunction(func_ref.GetHash()); - if (action) { - for (FxAstDocComment* comment : action->Declaration->DocComments) { - printf("[DOC] %.*s: ", action->Name->Length, action->Name->Start); + if (function) { + for (FoxAstDocComment* comment : function->Declaration->DocComments) { + printf("[DOC] %.*s: ", function->Name->Length, function->Name->Start); PrintDocComment(comment->Comment, mInCommandMode); } } @@ -227,21 +227,21 @@ FxAstNode* FxConfigScript::TryParseKeyword(FxAstBlock* parent_block) return nullptr; } -void FxConfigScript::PushScope() +void FoxConfigScript::PushScope() { - FxScriptScope* current = mCurrentScope; + FoxScope* current = mCurrentScope; - FxScriptScope* new_scope = mScopes.Insert(); + FoxScope* new_scope = mScopes.Insert(); new_scope->Parent = current; new_scope->Vars.Create(FX_SCRIPT_SCOPE_LOCAL_VARS_START_SIZE); - new_scope->Actions.Create(FX_SCRIPT_SCOPE_LOCAL_ACTIONS_START_SIZE); + new_scope->Functions.Create(FX_SCRIPT_SCOPE_LOCAL_ACTIONS_START_SIZE); mCurrentScope = new_scope; } -void FxConfigScript::PopScope() +void FoxConfigScript::PopScope() { - FxScriptScope* new_scope = mCurrentScope->Parent; + FoxScope* new_scope = mCurrentScope->Parent; mScopes.RemoveLast(); assert(new_scope == &mScopes.GetLast()); @@ -249,27 +249,27 @@ void FxConfigScript::PopScope() mCurrentScope = new_scope; } -FxAstVarDecl* FxConfigScript::InternalVarDeclare(FxTokenizer::Token* name_token, FxTokenizer::Token* type_token, FxScriptScope* scope) +FoxAstVarDecl* FoxConfigScript::InternalVarDeclare(FoxTokenizer::Token* name_token, FoxTokenizer::Token* type_token, FoxScope* scope) { if (scope == nullptr) { scope = mCurrentScope; } // Allocate the declaration node - FxAstVarDecl* node = FX_SCRIPT_ALLOC_NODE(FxAstVarDecl); + FoxAstVarDecl* node = FX_SCRIPT_ALLOC_NODE(FoxAstVarDecl); node->Name = name_token; node->Type = type_token; node->DefineAsGlobal = (scope == &mScopes[0]); // Push the variable to the scope - FxScriptVar var {name_token, type_token, scope}; + FoxVar var {name_token, type_token, scope}; scope->Vars.Insert(var); return node; } -FxAstVarDecl* FxConfigScript::ParseVarDeclare(FxScriptScope* scope) +FoxAstVarDecl* FoxConfigScript::ParseVarDeclare(FoxScope* scope) { if (scope == nullptr) { scope = mCurrentScope; @@ -278,13 +278,13 @@ FxAstVarDecl* FxConfigScript::ParseVarDeclare(FxScriptScope* scope) Token& type = EatToken(TT::Identifier); Token& name = EatToken(TT::Identifier); - FxAstVarDecl* node = FX_SCRIPT_ALLOC_NODE(FxAstVarDecl); + FoxAstVarDecl* node = FX_SCRIPT_ALLOC_NODE(FoxAstVarDecl); node->Name = &name; node->Type = &type; node->DefineAsGlobal = (scope == &mScopes[0]); - FxScriptVar var {&type, &name, scope}; + FoxVar var {&type, &name, scope}; node->Assignment = TryParseAssignment(node->Name); /*if (node->Assignment) { @@ -295,12 +295,12 @@ FxAstVarDecl* FxConfigScript::ParseVarDeclare(FxScriptScope* scope) return node; } -// FxScriptVar& FxConfigScript::ParseVarDeclare() +// FoxVar& FoxConfigScript::ParseVarDeclare() //{ // Token& type = EatToken(TT::Identifier); // Token& name = EatToken(TT::Identifier); // -// FxScriptVar var{ name.GetHash(), &type, &name }; +// FoxVar var{ name.GetHash(), &type, &name }; // // TryParseAssignment(var); // @@ -309,12 +309,12 @@ FxAstVarDecl* FxConfigScript::ParseVarDeclare(FxScriptScope* scope) // return mCurrentScope->Vars.GetLast(); // } -FxScriptVar* FxConfigScript::FindVar(FxHash hashed_name) +FoxVar* FoxConfigScript::FindVar(FoxHash hashed_name) { - FxScriptScope* scope = mCurrentScope; + FoxScope* scope = mCurrentScope; while (scope) { - FxScriptVar* var = scope->FindVarInScope(hashed_name); + FoxVar* var = scope->FindVarInScope(hashed_name); if (var) { return var; } @@ -325,9 +325,9 @@ FxScriptVar* FxConfigScript::FindVar(FxHash hashed_name) return nullptr; } -FxScriptExternalFunc* FxConfigScript::FindExternalAction(FxHash hashed_name) +FoxExternalFunc* FoxConfigScript::FindExternalFunction(FoxHash hashed_name) { - for (FxScriptExternalFunc& func : mExternalFuncs) { + for (FoxExternalFunc& func : mExternalFuncs) { if (func.HashedName == hashed_name) { return &func; } @@ -336,12 +336,12 @@ FxScriptExternalFunc* FxConfigScript::FindExternalAction(FxHash hashed_name) return nullptr; } -FxScriptAction* FxConfigScript::FindAction(FxHash hashed_name) +FoxFunction* FoxConfigScript::FindFunction(FoxHash hashed_name) { - FxScriptScope* scope = mCurrentScope; + FoxScope* scope = mCurrentScope; while (scope) { - FxScriptAction* var = scope->FindActionInScope(hashed_name); + FoxFunction* var = scope->FindFunctionInScope(hashed_name); if (var) { return var; } @@ -352,7 +352,7 @@ FxScriptAction* FxConfigScript::FindAction(FxHash hashed_name) return nullptr; } -void FxConfigScript::Execute(FxScriptVM& vm) +void FoxConfigScript::Execute(FoxVM& vm) { DefineDefaultExternalFunctions(); @@ -365,33 +365,33 @@ void FxConfigScript::Execute(FxScriptVM& vm) printf("\n=====\n"); - FxScriptIREmitter ir_emitter; + FoxIREmitter ir_emitter; ir_emitter.BeginEmitting(mRootBlock); printf("\n=====\n"); - FxScriptIRPrinter ir_printer(ir_emitter.mBytecode); + FoxIRPrinter ir_printer(ir_emitter.mBytecode); ir_printer.Print(); #if 0 - FxScriptBCEmitter emitter; + FoxBCEmitter emitter; emitter.BeginEmitting(mRootBlock); printf("\n=====\n"); - FxScriptBCPrinter printer(emitter.mBytecode); + FoxBCPrinter printer(emitter.mBytecode); printer.Print(); printf("\n=====\n"); - FxScriptTranspilerX86 transpiler(emitter.mBytecode); + FoxTranspilerX86 transpiler(emitter.mBytecode); transpiler.Print(); printf("\n=====\n"); - for (FxScriptBytecodeVarHandle& handle : emitter.VarHandles) { + for (FoxBytecodeVarHandle& handle : emitter.VarHandles) { printf("Var(%u) AT %lld\n", handle.HashedName, handle.Offset); } @@ -400,7 +400,7 @@ void FxConfigScript::Execute(FxScriptVM& vm) vm.mExternalFuncs = mExternalFuncs; vm.Start(std::move(emitter.mBytecode)); - for (FxScriptBytecodeVarHandle& handle : emitter.VarHandles) { + for (FoxBytecodeVarHandle& handle : emitter.VarHandles) { printf("Var(%u) AT %lld -> %u\n", handle.HashedName, handle.Offset, vm.Stack[handle.Offset]); } @@ -409,7 +409,7 @@ void FxConfigScript::Execute(FxScriptVM& vm) } #if 0 -bool FxConfigScript::ExecuteUserCommand(const char* command, FxScriptInterpreter& interpreter) +bool FoxConfigScript::ExecuteUserCommand(const char* command, FoxInterpreter& interpreter) { mHasErrors = false; @@ -428,15 +428,15 @@ bool FxConfigScript::ExecuteUserCommand(const char* command, FxScriptInterpreter char* data_buffer = FX_SCRIPT_ALLOC_MEMORY(char, length_of_command + 1); memcpy(data_buffer, command, length_of_command); - FxTokenizer tokenizer(data_buffer, length_of_command); + FoxTokenizer tokenizer(data_buffer, length_of_command); tokenizer.Tokenize(); - for (FxTokenizer::Token& token : tokenizer.GetTokens()) { + for (FoxTokenizer::Token& token : tokenizer.GetTokens()) { // token.Print(); mTokens.Insert(token); } - /*for (FxTokenizer::Token& token : mTokens) { + /*for (FoxTokenizer::Token& token : mTokens) { token.Print(); }*/ } @@ -444,14 +444,14 @@ bool FxConfigScript::ExecuteUserCommand(const char* command, FxScriptInterpreter mTokenIndex = new_token_index; mInCommandMode = true; - FxAstBlock* root_block = FX_SCRIPT_ALLOC_NODE(FxAstBlock); + FoxAstBlock* root_block = FX_SCRIPT_ALLOC_NODE(FoxAstBlock); - FxAstNode* statement; + FoxAstNode* statement; while ((statement = ParseStatementAsCommand(root_block))) { root_block->Statements.push_back(statement); } - // FxAstNode* node = ParseStatementAsCommand(); + // FoxAstNode* node = ParseStatementAsCommand(); // Revert the current state if there have been errors if (root_block == nullptr) { @@ -488,19 +488,19 @@ bool FxConfigScript::ExecuteUserCommand(const char* command, FxScriptInterpreter #endif -FxScriptValue FxConfigScript::ParseValue() +FoxValue FoxConfigScript::ParseValue() { Token& token = GetToken(); TT token_type = token.Type; - FxScriptValue value; + FoxValue value; if (token_type == TT::Identifier) { - FxScriptVar* var = FindVar(token.GetHash()); + FoxVar* var = FindVar(token.GetHash()); if (var) { - value.Type = FxScriptValue::REF; + value.Type = FoxValue::REF; - FxAstVarRef* var_ref = FX_SCRIPT_ALLOC_NODE(FxAstVarRef); + FoxAstVarRef* var_ref = FX_SCRIPT_ALLOC_NODE(FoxAstVarRef); var_ref->Name = var->Name; var_ref->Scope = var->Scope; @@ -526,17 +526,17 @@ FxScriptValue FxConfigScript::ParseValue() switch (token_type) { case TT::Integer: EatToken(TT::Integer); - value.Type = FxScriptValue::INT; + value.Type = FoxValue::INT; value.ValueInt = token.ToInt(); break; case TT::Float: EatToken(TT::Float); - value.Type = FxScriptValue::FLOAT; + value.Type = FoxValue::FLOAT; value.ValueFloat = token.ToFloat(); break; case TT::String: EatToken(TT::String); - value.Type = FxScriptValue::STRING; + value.Type = FoxValue::STRING; value.ValueString = token.GetHeapStr(); break; default:; @@ -551,12 +551,12 @@ FxScriptValue FxConfigScript::ParseValue() return (rval_); \ } -static bool IsTokenTypeLiteral(FxTokenizer::TokenType type) +static bool IsTokenTypeLiteral(FoxTokenizer::TokenType type) { return (type == TT::Integer || type == TT::Float || type == TT::String); } -FxAstNode* FxConfigScript::ParseRhs() +FoxAstNode* FoxConfigScript::ParseRhs() { RETURN_IF_NO_TOKENS(nullptr); @@ -572,31 +572,31 @@ FxAstNode* FxConfigScript::ParseRhs() } } - FxTokenizer::Token& token = GetToken(); + FoxTokenizer::Token& token = GetToken(); - FxAstNode* lhs = nullptr; + FoxAstNode* lhs = nullptr; if (token.Type == TT::Identifier) { if (has_parameters) { - lhs = ParseActionCall(); + lhs = ParseFunctionCall(); } else { - FxScriptExternalFunc* external_action = FindExternalAction(token.GetHash()); - if (external_action != nullptr) { - lhs = ParseActionCall(); + FoxExternalFunc* external_function = FindExternalFunction(token.GetHash()); + if (external_function != nullptr) { + lhs = ParseFunctionCall(); } - FxScriptAction* action = FindAction(token.GetHash()); - if (action != nullptr) { - lhs = ParseActionCall(); + FoxFunction* function = FindFunction(token.GetHash()); + if (function != nullptr) { + lhs = ParseFunctionCall(); } } } if (!lhs) { if (IsTokenTypeLiteral(token.Type) || token.Type == TT::Identifier) { - FxAstLiteral* literal = FX_SCRIPT_ALLOC_NODE(FxAstLiteral); + FoxAstLiteral* literal = FX_SCRIPT_ALLOC_NODE(FoxAstLiteral); - FxScriptValue value = ParseValue(); + FoxValue value = ParseValue(); literal->Value = value; lhs = literal; @@ -607,12 +607,12 @@ FxAstNode* FxConfigScript::ParseRhs() } - // FxAstLiteral* literal = FX_SCRIPT_ALLOC_NODE(FxAstLiteral); + // FoxAstLiteral* literal = FX_SCRIPT_ALLOC_NODE(FoxAstLiteral); // literal->Value = value; TT op_type = GetToken(0).Type; if (op_type == TT::Plus || op_type == TT::Minus) { - FxAstBinop* binop = FX_SCRIPT_ALLOC_NODE(FxAstBinop); + FoxAstBinop* binop = FX_SCRIPT_ALLOC_NODE(FoxAstBinop); binop->Left = lhs; binop->OpToken = &EatToken(op_type); @@ -638,37 +638,37 @@ FxAstNode* FxConfigScript::ParseRhs() } } - FxTokenizer::Token& token = GetToken(); + FoxTokenizer::Token& token = GetToken(); - FxAstNode* lhs = nullptr; + FoxAstNode* lhs = nullptr; if (token.Type == TT::Identifier) { if (has_parameters) { - lhs = ParseActionCall(); + lhs = ParseFunctionCall(); } else { - FxScriptExternalFunc* external_action = FindExternalAction(token.GetHash()); - if (external_action != nullptr) { - return ParseActionCall(); + FoxExternalFunc* external_function = FindExternalFunction(token.GetHash()); + if (external_function != nullptr) { + return ParseFunctionCall(); } - FxScriptAction* action = FindAction(token.GetHash()); - if (action != nullptr) { - return ParseActionCall(); + FoxFunction* function = FindFunction(token.GetHash()); + if (function != nullptr) { + return ParseFunctionCall(); } } } else if (IsTokenTypeLiteral(token.Type) || token.Type == TT::Identifier) { - FxAstLiteral* literal = FX_SCRIPT_ALLOC_NODE(FxAstLiteral); + FoxAstLiteral* literal = FX_SCRIPT_ALLOC_NODE(FoxAstLiteral); literal->Value = ParseValue(); lhs = literal; } TT op_type = GetToken(0).Type; if (op_type == TT::Plus || op_type == TT::Minus) { - FxAstBinop* binop = FX_SCRIPT_ALLOC_NODE(FxAstBinop); + FoxAstBinop* binop = FX_SCRIPT_ALLOC_NODE(FoxAstBinop); binop->Left = lhs; binop->OpToken = &EatToken(op_type); @@ -681,7 +681,7 @@ FxAstNode* FxConfigScript::ParseRhs() */ } -FxAstAssign* FxConfigScript::TryParseAssignment(FxTokenizer::Token* var_name) +FoxAstAssign* FoxConfigScript::TryParseAssignment(FoxTokenizer::Token* var_name) { if (GetToken().Type != TT::Equals) { return nullptr; @@ -689,9 +689,9 @@ FxAstAssign* FxConfigScript::TryParseAssignment(FxTokenizer::Token* var_name) EatToken(TT::Equals); - FxAstAssign* node = FX_SCRIPT_ALLOC_NODE(FxAstAssign); + FoxAstAssign* node = FX_SCRIPT_ALLOC_NODE(FoxAstAssign); - FxAstVarRef* var_ref = FX_SCRIPT_ALLOC_NODE(FxAstVarRef); + FoxAstVarRef* var_ref = FX_SCRIPT_ALLOC_NODE(FoxAstVarRef); var_ref->Name = var_name; var_ref->Scope = mCurrentScope; node->Var = var_ref; @@ -702,7 +702,7 @@ FxAstAssign* FxConfigScript::TryParseAssignment(FxTokenizer::Token* var_name) return node; } -void FxConfigScript::DefineExternalVar(const char* type, const char* name, const FxScriptValue& value) +void FoxConfigScript::DefineExternalVar(const char* type, const char* name, const FoxValue& value) { Token* name_token = FX_SCRIPT_ALLOC_MEMORY(Token, sizeof(Token)); Token* type_token = FX_SCRIPT_ALLOC_MEMORY(Token, sizeof(Token)); @@ -731,9 +731,9 @@ void FxConfigScript::DefineExternalVar(const char* type, const char* name, const name_token->Length = name_len + 1; } - FxScriptScope* definition_scope = &mScopes[0]; + FoxScope* definition_scope = &mScopes[0]; - FxScriptVar var(type_token, name_token, definition_scope, true); + FoxVar var(type_token, name_token, definition_scope, true); var.Value = value; definition_scope->Vars.Insert(var); @@ -743,7 +743,7 @@ void FxConfigScript::DefineExternalVar(const char* type, const char* name, const var.Type = nullptr; } -FxAstNode* FxConfigScript::ParseStatementAsCommand(FxAstBlock* parent_block) +FoxAstNode* FoxConfigScript::ParseStatementAsCommand(FoxAstBlock* parent_block) { if (mHasErrors) { return nullptr; @@ -760,7 +760,7 @@ FxAstNode* FxConfigScript::ParseStatementAsCommand(FxAstBlock* parent_block) } // Try to parse as a keyword first - FxAstNode* node = TryParseKeyword(parent_block); + FoxAstNode* node = TryParseKeyword(parent_block); if (node) { RETURN_IF_NO_TOKENS(node); @@ -783,14 +783,14 @@ FxAstNode* FxConfigScript::ParseStatementAsCommand(FxAstBlock* parent_block) } // If there is what looks to be a function call, try it else { - FxScriptExternalFunc* external_action = FindExternalAction(GetToken().GetHash()); - if (external_action != nullptr) { - node = ParseActionCall(); + FoxExternalFunc* external_function = FindExternalFunction(GetToken().GetHash()); + if (external_function != nullptr) { + node = ParseFunctionCall(); } else { - FxScriptAction* action = FindAction(GetToken().GetHash()); - if (action != nullptr) { - node = ParseActionCall(); + FoxFunction* function = FindFunction(GetToken().GetHash()); + if (function != nullptr) { + node = ParseFunctionCall(); } } } @@ -807,7 +807,7 @@ FxAstNode* FxConfigScript::ParseStatementAsCommand(FxAstBlock* parent_block) return node; } -FxAstNode* FxConfigScript::ParseStatement(FxAstBlock* parent_block) +FoxAstNode* FoxConfigScript::ParseStatement(FoxAstBlock* parent_block) { if (mHasErrors) { return nullptr; @@ -820,7 +820,7 @@ FxAstNode* FxConfigScript::ParseStatement(FxAstBlock* parent_block) mInCommandMode = true; - FxAstCommandMode* cmd_mode = FX_SCRIPT_ALLOC_NODE(FxAstCommandMode); + FoxAstCommandMode* cmd_mode = FX_SCRIPT_ALLOC_NODE(FoxAstCommandMode); cmd_mode->Node = ParseStatementAsCommand(parent_block); mInCommandMode = false; @@ -829,7 +829,7 @@ FxAstNode* FxConfigScript::ParseStatement(FxAstBlock* parent_block) } while (GetToken().Type == TT::DocComment) { - FxAstDocComment* comment = FX_SCRIPT_ALLOC_NODE(FxAstDocComment); + FoxAstDocComment* comment = FX_SCRIPT_ALLOC_NODE(FoxAstDocComment); comment->Comment = &EatToken(TT::DocComment); CurrentDocComments.push_back(comment); @@ -847,11 +847,11 @@ FxAstNode* FxConfigScript::ParseStatement(FxAstBlock* parent_block) } } - FxAstNode* node = TryParseKeyword(parent_block); + FoxAstNode* node = TryParseKeyword(parent_block); if (!node && (mTokenIndex < mTokens.Size() && GetToken().Type == TT::Identifier)) { if (mTokenIndex + 1 < mTokens.Size() && GetToken(1).Type == TT::LParen) { - node = ParseActionCall(); + node = ParseFunctionCall(); } else if (mTokenIndex + 1 < mTokens.Size() && GetToken(1).Type == TT::Equals) { Token& assign_name = EatToken(TT::Identifier); @@ -877,17 +877,17 @@ FxAstNode* FxConfigScript::ParseStatement(FxAstBlock* parent_block) return node; } -FxAstBlock* FxConfigScript::ParseBlock() +FoxAstBlock* FoxConfigScript::ParseBlock() { bool in_command = mInCommandMode; mInCommandMode = false; - FxAstBlock* block = FX_SCRIPT_ALLOC_NODE(FxAstBlock); + FoxAstBlock* block = FX_SCRIPT_ALLOC_NODE(FoxAstBlock); EatToken(TT::LBrace); while (GetToken().Type != TT::RBrace) { - FxAstNode* command = ParseStatement(block); + FoxAstNode* command = ParseStatement(block); if (command == nullptr) { break; } @@ -900,16 +900,16 @@ FxAstBlock* FxConfigScript::ParseBlock() return block; } -FxAstActionDecl* FxConfigScript::ParseActionDeclare() +FoxAstFunctionDecl* FoxConfigScript::ParseFunctionDeclare() { - FxAstActionDecl* node = FX_SCRIPT_ALLOC_NODE(FxAstActionDecl); + FoxAstFunctionDecl* node = FX_SCRIPT_ALLOC_NODE(FoxAstFunctionDecl); if (!CurrentDocComments.empty()) { node->DocComments = CurrentDocComments; CurrentDocComments.clear(); } - // Name of the action + // Name of the function Token& name = EatToken(TT::Identifier); node->Name = &name; @@ -917,7 +917,7 @@ FxAstActionDecl* FxConfigScript::ParseActionDeclare() PushScope(); EatToken(TT::LParen); - FxAstBlock* params = FX_SCRIPT_ALLOC_NODE(FxAstBlock); + FoxAstBlock* params = FX_SCRIPT_ALLOC_NODE(FoxAstBlock); // Parse the parameter list while (GetToken().Type != TT::RParen) { @@ -935,7 +935,7 @@ FxAstActionDecl* FxConfigScript::ParseActionDeclare() // Parse the return type /*if (GetToken().Type != TT::LBrace) { - FxAstVarDecl* return_decl = ParseVarDeclare(); + FoxAstVarDecl* return_decl = ParseVarDeclare(); node->ReturnVar = return_decl; }*/ @@ -946,7 +946,7 @@ FxAstActionDecl* FxConfigScript::ParseActionDeclare() // Get the token for the type Token& type_token = EatToken(TT::Identifier); - FxAstVarDecl* return_decl = InternalVarDeclare(mTokenReturnVar, &type_token); + FoxAstVarDecl* return_decl = InternalVarDeclare(mTokenReturnVar, &type_token); node->ReturnVar = return_decl; } @@ -956,17 +956,17 @@ FxAstActionDecl* FxConfigScript::ParseActionDeclare() node->Params = params; - FxScriptAction action(&name, mCurrentScope, node->Block, node); - mCurrentScope->Actions.Insert(action); + FoxFunction function(&name, mCurrentScope, node->Block, node); + mCurrentScope->Functions.Insert(function); return node; } -// FxScriptValue FxConfigScript::TryCallInternalFunc(FxHash func_name, std::vector& params) +// FoxValue FoxConfigScript::TryCallInternalFunc(FoxHash func_name, std::vector& params) //{ -// FxScriptValue return_value; +// FoxValue return_value; // -// for (const FxScriptInternalFunc& func : mInternalFuncs) { +// for (const FoxInternalFunc& func : mInternalFuncs) { // if (func.HashedName == func_name) { // func.Func(params, &return_value); // return return_value; @@ -976,14 +976,14 @@ FxAstActionDecl* FxConfigScript::ParseActionDeclare() // return return_value; // } -FxAstActionCall* FxConfigScript::ParseActionCall() +FoxAstFunctionCall* FoxConfigScript::ParseFunctionCall() { - FxAstActionCall* node = FX_SCRIPT_ALLOC_NODE(FxAstActionCall); + FoxAstFunctionCall* node = FX_SCRIPT_ALLOC_NODE(FoxAstFunctionCall); Token& name = EatToken(TT::Identifier); node->HashedName = name.GetHash(); - node->Action = FindAction(node->HashedName); + node->Function = FindFunction(node->HashedName); TT end_token_type = TT::Semicolon; @@ -996,7 +996,7 @@ FxAstActionCall* FxConfigScript::ParseActionCall() } while (GetToken().Type != end_token_type) { - FxAstNode* param = ParseRhs(); + FoxAstNode* param = ParseRhs(); if (param == nullptr) { break; @@ -1027,13 +1027,13 @@ FxAstActionCall* FxConfigScript::ParseActionCall() } -// void FxConfigScript::ParseDoCall() +// void FoxConfigScript::ParseDoCall() //{ // Token& call_name = EatToken(TT::Identifier); // // EatToken(TT::LParen); // -// std::vector params; +// std::vector params; // // while (true) { // params.push_back(ParseValue()); @@ -1060,11 +1060,11 @@ FxAstActionCall* FxConfigScript::ParseActionCall() // } -FxAstBlock* FxConfigScript::Parse() +FoxAstBlock* FoxConfigScript::Parse() { - FxAstBlock* root_block = FX_SCRIPT_ALLOC_NODE(FxAstBlock); + FoxAstBlock* root_block = FX_SCRIPT_ALLOC_NODE(FoxAstBlock); - FxAstNode* keyword; + FoxAstNode* keyword; while ((keyword = ParseStatement(root_block))) { root_block->Statements.push_back(keyword); } @@ -1077,39 +1077,39 @@ FxAstBlock* FxConfigScript::Parse() return nullptr; } - FxAstPrinter printer(root_block); + FoxAstPrinter printer(root_block); printer.Print(root_block); return root_block; } -void FxConfigScript::DefineDefaultExternalFunctions() +void FoxConfigScript::DefineDefaultExternalFunctions() { // log([int | float | string | ref] args...) RegisterExternalFunc( - FxHashStr("log"), {}, // Do not check argument types as we handle it here - [](FxScriptVM* vm, std::vector& args, FxScriptValue* return_value) + FoxHashStr("log"), {}, // Do not check argument types as we handle it here + [](FoxVM* vm, std::vector& args, FoxValue* return_value) { printf("[SCRIPT]: "); for (int i = args.size() - 1; i >= 0; i--) { - FxScriptValue& arg = args[i]; + FoxValue& arg = args[i]; - // const FxScriptValue& value = interpreter.GetImmediateValue(arg); - const FxScriptValue& value = arg; + // const FoxValue& value = interpreter.GetImmediateValue(arg); + const FoxValue& value = arg; switch (value.Type) { - case FxScriptValue::NONETYPE: + case FoxValue::NONETYPE: printf("[none]"); break; - case FxScriptValue::INT: + case FoxValue::INT: printf("%d", value.ValueInt); break; - case FxScriptValue::FLOAT: + case FoxValue::FLOAT: printf("%f", value.ValueFloat); break; - case FxScriptValue::STRING: + case FoxValue::STRING: printf("%s", value.ValueString); break; default: @@ -1127,10 +1127,10 @@ void FxConfigScript::DefineDefaultExternalFunctions() } -void FxConfigScript::RegisterExternalFunc(FxHash func_name, std::vector param_types, - FxScriptExternalFunc::FuncType callback, bool is_variadic) +void FoxConfigScript::RegisterExternalFunc(FoxHash func_name, std::vector param_types, FoxExternalFunc::FuncType callback, + bool is_variadic) { - FxScriptExternalFunc func { + FoxExternalFunc func { .HashedName = func_name, .Function = callback, .ParameterTypes = param_types, @@ -1147,9 +1147,9 @@ void FxConfigScript::RegisterExternalFunc(FxHash func_name, std::vectorNodeType == FX_AST_BLOCK) { - return EmitBlock(reinterpret_cast(node)); + return EmitBlock(reinterpret_cast(node)); } else if (node->NodeType == FX_AST_ACTIONDECL) { - return EmitAction(reinterpret_cast(node)); + return EmitFunction(reinterpret_cast(node)); } else if (node->NodeType == FX_AST_ACTIONCALL) { - return DoActionCall(reinterpret_cast(node)); + return DoFunctionCall(reinterpret_cast(node)); } else if (node->NodeType == FX_AST_ASSIGN) { - return EmitAssign(reinterpret_cast(node)); + return EmitAssign(reinterpret_cast(node)); } else if (node->NodeType == FX_AST_VARDECL) { - DoVarDeclare(reinterpret_cast(node)); + DoVarDeclare(reinterpret_cast(node)); return; } else if (node->NodeType == FX_AST_RETURN) { - constexpr FxHash return_val_hash = FxHashStr(FX_SCRIPT_VAR_RETURN_VAL); + constexpr FoxHash return_val_hash = FoxHashStr(FX_SCRIPT_VAR_RETURN_VAL); - FxScriptBytecodeVarHandle* return_var = FindVarHandle(return_val_hash); + FoxBytecodeVarHandle* return_var = FindVarHandle(return_val_hash); if (return_var) { DoLoad(return_var->Offset, FX_REG_XR); @@ -1211,9 +1211,9 @@ void FxScriptBCEmitter::Emit(FxAstNode* node) } } -FxScriptBytecodeVarHandle* FxScriptBCEmitter::FindVarHandle(FxHash hashed_name) +FoxBytecodeVarHandle* FoxBCEmitter::FindVarHandle(FoxHash hashed_name) { - for (FxScriptBytecodeVarHandle& handle : VarHandles) { + for (FoxBytecodeVarHandle& handle : VarHandles) { if (handle.HashedName == hashed_name) { return &handle; } @@ -1221,9 +1221,9 @@ FxScriptBytecodeVarHandle* FxScriptBCEmitter::FindVarHandle(FxHash hashed_name) return nullptr; } -FxScriptBytecodeActionHandle* FxScriptBCEmitter::FindActionHandle(FxHash hashed_name) +FoxBytecodeFunctionHandle* FoxBCEmitter::FindFunctionHandle(FoxHash hashed_name) { - for (FxScriptBytecodeActionHandle& handle : ActionHandles) { + for (FoxBytecodeFunctionHandle& handle : FunctionHandles) { if (handle.HashedName == hashed_name) { return &handle; } @@ -1232,7 +1232,7 @@ FxScriptBytecodeActionHandle* FxScriptBCEmitter::FindActionHandle(FxHash hashed_ } -FxScriptRegister FxScriptBCEmitter::FindFreeRegister() +FoxBCRegister FoxBCEmitter::FindFreeRegister() { uint16 gp_r = 0x01; @@ -1243,16 +1243,16 @@ FxScriptRegister FxScriptBCEmitter::FindFreeRegister() // We are starting on 0x01, so register index should be N + 1 const int register_index = i + 1; - return static_cast(register_index); + return static_cast(register_index); } gp_r <<= 1; } - return FxScriptRegister::FX_REG_NONE; + return FoxBCRegister::FX_REG_NONE; } -const char* FxScriptBCEmitter::GetRegisterName(FxScriptRegister reg) +const char* FoxBCEmitter::GetRegisterName(FoxBCRegister reg) { switch (reg) { case FX_REG_NONE: @@ -1277,7 +1277,7 @@ const char* FxScriptBCEmitter::GetRegisterName(FxScriptRegister reg) return "NONE"; } -FxScriptRegister FxScriptBCEmitter::RegFlagToReg(FxScriptRegisterFlag reg_flag) +FoxBCRegister FoxBCEmitter::RegFlagToReg(FoxRegisterFlag reg_flag) { switch (reg_flag) { case FX_REGFLAG_NONE: @@ -1299,7 +1299,7 @@ FxScriptRegister FxScriptBCEmitter::RegFlagToReg(FxScriptRegisterFlag reg_flag) return FX_REG_NONE; } -FxScriptRegisterFlag FxScriptBCEmitter::RegToRegFlag(FxScriptRegister reg) +FoxRegisterFlag FoxBCEmitter::RegToRegFlag(FoxBCRegister reg) { switch (reg) { case FX_REG_NONE: @@ -1325,25 +1325,25 @@ FxScriptRegisterFlag FxScriptBCEmitter::RegToRegFlag(FxScriptRegister reg) } -void FxScriptBCEmitter::Write16(uint16 value) +void FoxBCEmitter::Write16(uint16 value) { mBytecode.Insert(static_cast(value >> 8)); mBytecode.Insert(static_cast(value)); } -void FxScriptBCEmitter::Write32(uint32 value) +void FoxBCEmitter::Write32(uint32 value) { Write16(static_cast(value >> 16)); Write16(static_cast(value)); } -void FxScriptBCEmitter::WriteOp(uint8 op_base, uint8 op_spec) +void FoxBCEmitter::WriteOp(uint8 op_base, uint8 op_spec) { mBytecode.Insert(op_base); mBytecode.Insert(op_spec); } -using RhsMode = FxScriptBCEmitter::RhsMode; +using RhsMode = FoxBCEmitter::RhsMode; #define MARK_REGISTER_USED(regn_) \ { \ @@ -1354,20 +1354,20 @@ using RhsMode = FxScriptBCEmitter::RhsMode; MarkRegisterFree(regn_); \ } -void FxScriptBCEmitter::MarkRegisterUsed(FxScriptRegister reg) +void FoxBCEmitter::MarkRegisterUsed(FoxBCRegister reg) { - FxScriptRegisterFlag rflag = RegToRegFlag(reg); - mRegsInUse = static_cast(uint16(mRegsInUse) | uint16(rflag)); + FoxRegisterFlag rflag = RegToRegFlag(reg); + mRegsInUse = static_cast(uint16(mRegsInUse) | uint16(rflag)); } -void FxScriptBCEmitter::MarkRegisterFree(FxScriptRegister reg) +void FoxBCEmitter::MarkRegisterFree(FoxBCRegister reg) { - FxScriptRegisterFlag rflag = RegToRegFlag(reg); + FoxRegisterFlag rflag = RegToRegFlag(reg); - mRegsInUse = static_cast(uint16(mRegsInUse) & (~uint16(rflag))); + mRegsInUse = static_cast(uint16(mRegsInUse) & (~uint16(rflag))); } -void FxScriptBCEmitter::EmitSave32(int16 offset, uint32 value) +void FoxBCEmitter::EmitSave32(int16 offset, uint32 value) { // SAVE32 [i16 offset] [i32] WriteOp(OpBase_Save, OpSpecSave_Int32); @@ -1376,7 +1376,7 @@ void FxScriptBCEmitter::EmitSave32(int16 offset, uint32 value) Write32(value); } -void FxScriptBCEmitter::EmitSaveReg32(int16 offset, FxScriptRegister reg) +void FoxBCEmitter::EmitSaveReg32(int16 offset, FoxBCRegister reg) { // SAVE32r [i16 offset] [%r32] WriteOp(OpBase_Save, OpSpecSave_Reg32); @@ -1386,7 +1386,7 @@ void FxScriptBCEmitter::EmitSaveReg32(int16 offset, FxScriptRegister reg) } -void FxScriptBCEmitter::EmitSaveAbsolute32(uint32 position, uint32 value) +void FoxBCEmitter::EmitSaveAbsolute32(uint32 position, uint32 value) { // SAVE32a [i32 offset] [i32] WriteOp(OpBase_Save, OpSpecSave_AbsoluteInt32); @@ -1395,7 +1395,7 @@ void FxScriptBCEmitter::EmitSaveAbsolute32(uint32 position, uint32 value) Write32(value); } -void FxScriptBCEmitter::EmitSaveAbsoluteReg32(uint32 position, FxScriptRegister reg) +void FoxBCEmitter::EmitSaveAbsoluteReg32(uint32 position, FoxBCRegister reg) { // SAVE32r [i32 offset] [%r32] WriteOp(OpBase_Save, OpSpecSave_AbsoluteReg32); @@ -1404,7 +1404,7 @@ void FxScriptBCEmitter::EmitSaveAbsoluteReg32(uint32 position, FxScriptRegister Write16(reg); } -void FxScriptBCEmitter::EmitPush32(uint32 value) +void FoxBCEmitter::EmitPush32(uint32 value) { // PUSH32 [i32] WriteOp(OpBase_Push, OpSpecPush_Int32); @@ -1413,7 +1413,7 @@ void FxScriptBCEmitter::EmitPush32(uint32 value) mStackOffset += 4; } -void FxScriptBCEmitter::EmitPush32r(FxScriptRegister reg) +void FoxBCEmitter::EmitPush32r(FoxBCRegister reg) { // PUSH32r [%r32] WriteOp(OpBase_Push, OpSpecPush_Reg32); @@ -1423,7 +1423,7 @@ void FxScriptBCEmitter::EmitPush32r(FxScriptRegister reg) } -void FxScriptBCEmitter::EmitPop32(FxScriptRegister output_reg) +void FoxBCEmitter::EmitPop32(FoxBCRegister output_reg) { // POP32 [%r32] WriteOp(OpBase_Pop, (OpSpecPop_Int32 << 4) | (output_reg & 0x0F)); @@ -1431,80 +1431,80 @@ void FxScriptBCEmitter::EmitPop32(FxScriptRegister output_reg) mStackOffset -= 4; } -void FxScriptBCEmitter::EmitLoad32(int offset, FxScriptRegister output_reg) +void FoxBCEmitter::EmitLoad32(int offset, FoxBCRegister output_reg) { // LOAD [i16] [%r32] WriteOp(OpBase_Load, (OpSpecLoad_Int32 << 4) | (output_reg & 0x0F)); Write16(static_cast(offset)); } -void FxScriptBCEmitter::EmitLoadAbsolute32(uint32 position, FxScriptRegister output_reg) +void FoxBCEmitter::EmitLoadAbsolute32(uint32 position, FoxBCRegister output_reg) { // LOADA [i32] [%r32] WriteOp(OpBase_Load, (OpSpecLoad_AbsoluteInt32 << 4) | (output_reg & 0x0F)); Write32(position); } -void FxScriptBCEmitter::EmitJumpRelative(uint16 offset) +void FoxBCEmitter::EmitJumpRelative(uint16 offset) { WriteOp(OpBase_Jump, OpSpecJump_Relative); Write16(offset); } -void FxScriptBCEmitter::EmitJumpAbsolute(uint32 position) +void FoxBCEmitter::EmitJumpAbsolute(uint32 position) { WriteOp(OpBase_Jump, OpSpecJump_Absolute); Write32(position); } -void FxScriptBCEmitter::EmitJumpAbsoluteReg32(FxScriptRegister reg) +void FoxBCEmitter::EmitJumpAbsoluteReg32(FoxBCRegister reg) { WriteOp(OpBase_Jump, OpSpecJump_AbsoluteReg32); Write16(reg); } -void FxScriptBCEmitter::EmitJumpCallAbsolute(uint32 position) +void FoxBCEmitter::EmitJumpCallAbsolute(uint32 position) { WriteOp(OpBase_Jump, OpSpecJump_CallAbsolute); Write32(position); } -void FxScriptBCEmitter::EmitJumpCallExternal(FxHash hashed_name) +void FoxBCEmitter::EmitJumpCallExternal(FoxHash hashed_name) { WriteOp(OpBase_Jump, OpSpecJump_CallExternal); Write32(hashed_name); } -void FxScriptBCEmitter::EmitJumpReturnToCaller() +void FoxBCEmitter::EmitJumpReturnToCaller() { WriteOp(OpBase_Jump, OpSpecJump_ReturnToCaller); } -void FxScriptBCEmitter::EmitMoveInt32(FxScriptRegister reg, uint32 value) +void FoxBCEmitter::EmitMoveInt32(FoxBCRegister reg, uint32 value) { WriteOp(OpBase_Move, (OpSpecMove_Int32 << 4) | (reg & 0x0F)); Write32(value); } -void FxScriptBCEmitter::EmitParamsStart() +void FoxBCEmitter::EmitParamsStart() { WriteOp(OpBase_Data, OpSpecData_ParamsStart); } -void FxScriptBCEmitter::EmitType(FxScriptValue::ValueType type) +void FoxBCEmitter::EmitType(FoxValue::ValueType type) { OpSpecType op_type = OpSpecType_Int; - if (type == FxScriptValue::STRING) { + if (type == FoxValue::STRING) { op_type = OpSpecType_String; } WriteOp(OpBase_Type, op_type); } -uint32 FxScriptBCEmitter::EmitDataString(char* str, uint16 length) +uint32 FoxBCEmitter::EmitDataString(char* str, uint16 length) { WriteOp(OpBase_Data, OpSpecData_String); @@ -1534,20 +1534,20 @@ uint32 FxScriptBCEmitter::EmitDataString(char* str, uint16 length) } -FxScriptRegister FxScriptBCEmitter::EmitBinop(FxAstBinop* binop, FxScriptBytecodeVarHandle* handle) +FoxBCRegister FoxBCEmitter::EmitBinop(FoxAstBinop* binop, FoxBytecodeVarHandle* handle) { bool will_preserve_lhs = false; // Load the A and B values into the registers - FxScriptRegister a_reg = EmitRhs(binop->Left, RhsMode::RHS_FETCH_TO_REGISTER, handle); + FoxBCRegister a_reg = EmitRhs(binop->Left, RhsMode::RHS_FETCH_TO_REGISTER, handle); - // Since there is a chance that this register will be clobbered (by binop, action call, etc), we will + // Since there is a chance that this register will be clobbered (by binop, function call, etc), we will // push the value of the register here and return it after processing the RHS if (binop->Right->NodeType != FX_AST_LITERAL) { will_preserve_lhs = true; EmitPush32r(a_reg); } - FxScriptRegister b_reg = EmitRhs(binop->Right, RhsMode::RHS_FETCH_TO_REGISTER, handle); + FoxBCRegister b_reg = EmitRhs(binop->Right, RhsMode::RHS_FETCH_TO_REGISTER, handle); // Retrieve the previous LHS if (will_preserve_lhs) { @@ -1568,9 +1568,9 @@ FxScriptRegister FxScriptBCEmitter::EmitBinop(FxAstBinop* binop, FxScriptBytecod return FX_REG_XR; } -FxScriptRegister FxScriptBCEmitter::EmitVarFetch(FxAstVarRef* ref, RhsMode mode) +FoxBCRegister FoxBCEmitter::EmitVarFetch(FoxAstVarRef* ref, RhsMode mode) { - FxScriptBytecodeVarHandle* var_handle = FindVarHandle(ref->Name->GetHash()); + FoxBytecodeVarHandle* var_handle = FindVarHandle(ref->Name->GetHash()); bool force_absolute_load = false; @@ -1585,7 +1585,7 @@ FxScriptRegister FxScriptBCEmitter::EmitVarFetch(FxAstVarRef* ref, RhsMode mode) return FX_REG_NONE; } - FxScriptRegister reg = FindFreeRegister(); + FoxBCRegister reg = FindFreeRegister(); MARK_REGISTER_USED(reg); @@ -1598,7 +1598,7 @@ FxScriptRegister FxScriptBCEmitter::EmitVarFetch(FxAstVarRef* ref, RhsMode mode) // If we are just copying the variable to this new variable, we can free the register after // we push to the stack. if (mode == RhsMode::RHS_DEFINE_IN_MEMORY) { - if (var_handle->Type == FxScriptValue::STRING) { + if (var_handle->Type == FoxValue::STRING) { EmitType(var_handle->Type); } @@ -1612,7 +1612,7 @@ FxScriptRegister FxScriptBCEmitter::EmitVarFetch(FxAstVarRef* ref, RhsMode mode) return reg; } -void FxScriptBCEmitter::DoLoad(uint32 stack_offset, FxScriptRegister output_reg, bool force_absolute) +void FoxBCEmitter::DoLoad(uint32 stack_offset, FoxBCRegister output_reg, bool force_absolute) { if (stack_offset < 0xFFFE && !force_absolute) { // Relative load @@ -1628,7 +1628,7 @@ void FxScriptBCEmitter::DoLoad(uint32 stack_offset, FxScriptRegister output_reg, } } -void FxScriptBCEmitter::DoSaveInt32(uint32 stack_offset, uint32 value, bool force_absolute) +void FoxBCEmitter::DoSaveInt32(uint32 stack_offset, uint32 value, bool force_absolute) { if (stack_offset < 0xFFFE && !force_absolute) { // Relative save @@ -1644,7 +1644,7 @@ void FxScriptBCEmitter::DoSaveInt32(uint32 stack_offset, uint32 value, bool forc } } -void FxScriptBCEmitter::DoSaveReg32(uint32 stack_offset, FxScriptRegister reg, bool force_absolute) +void FoxBCEmitter::DoSaveReg32(uint32 stack_offset, FoxBCRegister reg, bool force_absolute) { if (stack_offset < 0xFFFE && !force_absolute) { // Relative save @@ -1660,9 +1660,9 @@ void FxScriptBCEmitter::DoSaveReg32(uint32 stack_offset, FxScriptRegister reg, b } } -void FxScriptBCEmitter::EmitAssign(FxAstAssign* assign) +void FoxBCEmitter::EmitAssign(FoxAstAssign* assign) { - FxScriptBytecodeVarHandle* var_handle = FindVarHandle(assign->Var->Name->GetHash()); + FoxBytecodeVarHandle* var_handle = FindVarHandle(assign->Var->Name->GetHash()); if (var_handle == nullptr) { printf("!!! Var '%.*s' does not exist!\n", assign->Var->Name->Length, assign->Var->Name->Start); return; @@ -1684,7 +1684,7 @@ void FxScriptBCEmitter::EmitAssign(FxAstAssign* assign) EmitRhs(assign->Rhs, RhsMode::RHS_ASSIGN_TO_HANDLE, var_handle); } -FxScriptRegister FxScriptBCEmitter::EmitLiteralInt(FxAstLiteral* literal, RhsMode mode, FxScriptBytecodeVarHandle* handle) +FoxBCRegister FoxBCEmitter::EmitLiteralInt(FoxAstLiteral* literal, RhsMode mode, FoxBytecodeVarHandle* handle) { // If this is on variable definition, push the value to the stack. if (mode == RhsMode::RHS_DEFINE_IN_MEMORY) { @@ -1697,7 +1697,7 @@ FxScriptRegister FxScriptBCEmitter::EmitLiteralInt(FxAstLiteral* literal, RhsMod else if (mode == RhsMode::RHS_FETCH_TO_REGISTER) { // EmitPush32(literal->Value.ValueInt); - FxScriptRegister output_reg = FindFreeRegister(); + FoxBCRegister output_reg = FindFreeRegister(); // EmitPop32(output_reg); EmitMoveInt32(output_reg, literal->Value.ValueInt); @@ -1719,7 +1719,7 @@ FxScriptRegister FxScriptBCEmitter::EmitLiteralInt(FxAstLiteral* literal, RhsMod } -FxScriptRegister FxScriptBCEmitter::EmitLiteralString(FxAstLiteral* literal, RhsMode mode, FxScriptBytecodeVarHandle* handle) +FoxBCRegister FoxBCEmitter::EmitLiteralString(FoxAstLiteral* literal, RhsMode mode, FoxBytecodeVarHandle* handle) { const uint32 string_length = strlen(literal->Value.ValueString); @@ -1729,7 +1729,7 @@ FxScriptRegister FxScriptBCEmitter::EmitLiteralString(FxAstLiteral* literal, Rhs // local string some_value = "Some String"; if (mode == RhsMode::RHS_DEFINE_IN_MEMORY) { // Push the location and mark it as a pointer to a string - EmitType(FxScriptValue::STRING); + EmitType(FoxValue::STRING); EmitPush32(string_position); return FX_REG_NONE; @@ -1738,13 +1738,13 @@ FxScriptRegister FxScriptBCEmitter::EmitLiteralString(FxAstLiteral* literal, Rhs // some_function("Some String") else if (mode == RhsMode::RHS_FETCH_TO_REGISTER) { // Push the location for the string and pop it back to a register. - EmitType(FxScriptValue::STRING); + EmitType(FoxValue::STRING); // Push the string position // EmitPush32(string_position); // Find a register to output to and write the index - FxScriptRegister output_reg = FindFreeRegister(); + FoxBCRegister output_reg = FindFreeRegister(); // EmitPop32(output_reg); EmitMoveInt32(output_reg, string_position); @@ -1760,7 +1760,7 @@ FxScriptRegister FxScriptBCEmitter::EmitLiteralString(FxAstLiteral* literal, Rhs const bool force_absolute_save = (handle->ScopeIndex < mScopeIndex); DoSaveInt32(handle->Offset, string_position, force_absolute_save); - handle->Type = FxScriptValue::STRING; + handle->Type = FoxValue::STRING; return FX_REG_NONE; } @@ -1768,20 +1768,20 @@ FxScriptRegister FxScriptBCEmitter::EmitLiteralString(FxAstLiteral* literal, Rhs return FX_REG_NONE; } -FxScriptRegister FxScriptBCEmitter::EmitRhs(FxAstNode* rhs, FxScriptBCEmitter::RhsMode mode, FxScriptBytecodeVarHandle* handle) +FoxBCRegister FoxBCEmitter::EmitRhs(FoxAstNode* rhs, FoxBCEmitter::RhsMode mode, FoxBytecodeVarHandle* handle) { if (rhs->NodeType == FX_AST_LITERAL) { - FxAstLiteral* literal = reinterpret_cast(rhs); + FoxAstLiteral* literal = reinterpret_cast(rhs); - if (literal->Value.Type == FxScriptValue::INT) { + if (literal->Value.Type == FoxValue::INT) { return EmitLiteralInt(literal, mode, handle); } - else if (literal->Value.Type == FxScriptValue::STRING) { + else if (literal->Value.Type == FoxValue::STRING) { return EmitLiteralString(literal, mode, handle); } - else if (literal->Value.Type == FxScriptValue::REF) { + else if (literal->Value.Type == FoxValue::REF) { // Reference another value, load from memory into register - FxScriptRegister output_register = EmitVarFetch(literal->Value.ValueRef, mode); + FoxBCRegister output_register = EmitVarFetch(literal->Value.ValueRef, mode); if (mode == RhsMode::RHS_ASSIGN_TO_HANDLE) { DoSaveReg32(handle->Offset, output_register); } @@ -1793,15 +1793,15 @@ FxScriptRegister FxScriptBCEmitter::EmitRhs(FxAstNode* rhs, FxScriptBCEmitter::R } else if (rhs->NodeType == FX_AST_ACTIONCALL || rhs->NodeType == FX_AST_BINOP) { - FxScriptRegister result_register = FX_REG_XR; + FoxBCRegister result_register = FX_REG_XR; if (rhs->NodeType == FX_AST_BINOP) { - result_register = EmitBinop(reinterpret_cast(rhs), handle); + result_register = EmitBinop(reinterpret_cast(rhs), handle); } else if (rhs->NodeType == FX_AST_ACTIONCALL) { - DoActionCall(reinterpret_cast(rhs)); - // Action results are stored in XR + DoFunctionCall(reinterpret_cast(rhs)); + // Function results are stored in XR result_register = FX_REG_XR; } @@ -1822,7 +1822,7 @@ FxScriptRegister FxScriptBCEmitter::EmitRhs(FxAstNode* rhs, FxScriptBCEmitter::R EmitPush32r(result_register); // Find a register to output to, and pop the value to there. - FxScriptRegister output_reg = FindFreeRegister(); + FoxBCRegister output_reg = FindFreeRegister(); EmitPop32(output_reg); // Mark the output register as used to store it @@ -1843,29 +1843,29 @@ FxScriptRegister FxScriptBCEmitter::EmitRhs(FxAstNode* rhs, FxScriptBCEmitter::R return FX_REG_NONE; } -FxScriptBytecodeVarHandle* FxScriptBCEmitter::DoVarDeclare(FxAstVarDecl* decl, VarDeclareMode mode) +FoxBytecodeVarHandle* FoxBCEmitter::DoVarDeclare(FoxAstVarDecl* decl, VarDeclareMode mode) { RETURN_VALUE_IF_NO_NODE(decl, nullptr); const uint16 size_of_type = static_cast(sizeof(int32)); - const FxHash type_int = FxHashStr("int"); - const FxHash type_string = FxHashStr("string"); + const FoxHash type_int = FoxHashStr("int"); + const FoxHash type_string = FoxHashStr("string"); - FxHash decl_hash = decl->Name->GetHash(); + FoxHash decl_hash = decl->Name->GetHash(); - FxScriptValue::ValueType value_type = FxScriptValue::INT; + FoxValue::ValueType value_type = FoxValue::INT; switch (decl_hash) { case type_int: - value_type = FxScriptValue::INT; + value_type = FoxValue::INT; break; case type_string: - value_type = FxScriptValue::STRING; + value_type = FoxValue::STRING; break; }; - FxScriptBytecodeVarHandle handle { + FoxBytecodeVarHandle handle { .HashedName = decl->Name->GetHash(), .Type = value_type, // Just int for now .Offset = (mStackOffset), @@ -1875,7 +1875,7 @@ FxScriptBytecodeVarHandle* FxScriptBCEmitter::DoVarDeclare(FxAstVarDecl* decl, V VarHandles.Insert(handle); - FxScriptBytecodeVarHandle* inserted_handle = &VarHandles[VarHandles.Size() - 1]; + FoxBytecodeVarHandle* inserted_handle = &VarHandles[VarHandles.Size() - 1]; if (mode == DECLARE_NO_EMIT) { // Do not emit any values @@ -1884,7 +1884,7 @@ FxScriptBytecodeVarHandle* FxScriptBCEmitter::DoVarDeclare(FxAstVarDecl* decl, V if (decl->Assignment) { - FxAstNode* rhs = decl->Assignment->Rhs; + FoxAstNode* rhs = decl->Assignment->Rhs; EmitRhs(rhs, RhsMode::RHS_DEFINE_IN_MEMORY, inserted_handle); @@ -1902,19 +1902,19 @@ FxScriptBytecodeVarHandle* FxScriptBCEmitter::DoVarDeclare(FxAstVarDecl* decl, V return inserted_handle; } -void FxScriptBCEmitter::DoActionCall(FxAstActionCall* call) +void FoxBCEmitter::DoFunctionCall(FoxAstFunctionCall* call) { RETURN_IF_NO_NODE(call); - FxScriptBytecodeActionHandle* handle = FindActionHandle(call->HashedName); + FoxBytecodeFunctionHandle* handle = FindFunctionHandle(call->HashedName); std::vector call_locations; call_locations.reserve(8); // Push all params to stack - for (FxAstNode* param : call->Params) { - // FxScriptRegister reg = + for (FoxAstNode* param : call->Params) { + // FoxBCRegister reg = if (param->NodeType == FX_AST_ACTIONCALL) { EmitRhs(param, RhsMode::RHS_DEFINE_IN_MEMORY, nullptr); call_locations.push_back(mStackOffset - 4); @@ -1929,9 +1929,9 @@ void FxScriptBCEmitter::DoActionCall(FxAstActionCall* call) int call_location_index = 0; // Push all params to stack - for (FxAstNode* param : call->Params) { + for (FoxAstNode* param : call->Params) { if (param->NodeType == FX_AST_ACTIONCALL) { - FxScriptRegister temp_register = FindFreeRegister(); + FoxBCRegister temp_register = FindFreeRegister(); DoLoad(call_locations[call_location_index], temp_register); call_location_index++; @@ -1965,7 +1965,7 @@ void FxScriptBCEmitter::DoActionCall(FxAstActionCall* call) EmitPop32(FX_REG_RA); } -FxScriptBytecodeVarHandle* FxScriptBCEmitter::DefineAndFetchParam(FxAstNode* param_decl_node) +FoxBytecodeVarHandle* FoxBCEmitter::DefineAndFetchParam(FoxAstNode* param_decl_node) { if (param_decl_node->NodeType != FX_AST_VARDECL) { printf("!!! param node type is not vardecl!\n"); @@ -1973,7 +1973,7 @@ FxScriptBytecodeVarHandle* FxScriptBCEmitter::DefineAndFetchParam(FxAstNode* par } // Emit variable without emitting pushes or pops - FxScriptBytecodeVarHandle* handle = DoVarDeclare(reinterpret_cast(param_decl_node), DECLARE_NO_EMIT); + FoxBytecodeVarHandle* handle = DoVarDeclare(reinterpret_cast(param_decl_node), DECLARE_NO_EMIT); if (!handle) { printf("!!! could not define and fetch param!\n"); @@ -1987,57 +1987,57 @@ FxScriptBytecodeVarHandle* FxScriptBCEmitter::DefineAndFetchParam(FxAstNode* par return handle; } -FxScriptBytecodeVarHandle* FxScriptBCEmitter::DefineReturnVar(FxAstVarDecl* decl) +FoxBytecodeVarHandle* FoxBCEmitter::DefineReturnVar(FoxAstVarDecl* decl) { RETURN_VALUE_IF_NO_NODE(decl, nullptr); return DoVarDeclare(decl); } -void FxScriptBCEmitter::EmitAction(FxAstActionDecl* action) +void FoxBCEmitter::EmitFunction(FoxAstFunctionDecl* function) { - RETURN_IF_NO_NODE(action); + RETURN_IF_NO_NODE(function); ++mScopeIndex; - // Store the bytecode offset before the action is emitted + // Store the bytecode offset before the function is emitted - const size_t start_of_action = mBytecode.Size(); - printf("Start of action %zu\n", start_of_action); + const size_t start_of_function = mBytecode.Size(); + printf("Start of function %zu\n", start_of_function); // Emit the jump instruction, we will update the jump position after emitting all of the code inside the block EmitJumpRelative(0); // const uint32 initial_stack_offset = mStackOffset; - const size_t header_jump_start_index = start_of_action + sizeof(uint16); + const size_t header_jump_start_index = start_of_function + sizeof(uint16); size_t start_var_handle_count = VarHandles.Size(); // Offset for the pushed return address mStackOffset += 4; - // Emit the body of the action + // Emit the body of the function { - for (FxAstNode* param_decl_node : action->Params->Statements) { + for (FoxAstNode* param_decl_node : function->Params->Statements) { DefineAndFetchParam(param_decl_node); } - FxScriptBytecodeVarHandle* return_var = DefineReturnVar(action->ReturnVar); + FoxBytecodeVarHandle* return_var = DefineReturnVar(function->ReturnVar); - EmitBlock(action->Block); + EmitBlock(function->Block); - // Check to see if there has been a return statement in the action + // Check to see if there has been a return statement in the function bool block_has_return = false; - for (FxAstNode* statement : action->Block->Statements) { + for (FoxAstNode* statement : function->Block->Statements) { if (statement->NodeType == FX_AST_RETURN) { block_has_return = true; break; } } - // There is no return statement in the action's block, add a return statement + // There is no return statement in the function's block, add a return statement if (!block_has_return) { EmitJumpReturnToCaller(); @@ -2050,40 +2050,40 @@ void FxScriptBCEmitter::EmitAction(FxAstActionDecl* action) // Return offset back to pre-call mStackOffset -= 4; - const size_t end_of_action = mBytecode.Size(); - const uint16 distance_to_action = static_cast(end_of_action - (start_of_action)-4); + const size_t end_of_function = mBytecode.Size(); + const uint16 distance_to_function = static_cast(end_of_function - (start_of_function)-4); - // Update the jump to the end of the action - mBytecode[header_jump_start_index] = static_cast(distance_to_action >> 8); - mBytecode[header_jump_start_index + 1] = static_cast((distance_to_action & 0xFF)); + // Update the jump to the end of the function + mBytecode[header_jump_start_index] = static_cast(distance_to_function >> 8); + mBytecode[header_jump_start_index + 1] = static_cast((distance_to_function & 0xFF)); - FxScriptBytecodeActionHandle action_handle {.HashedName = action->Name->GetHash(), .BytecodeIndex = static_cast(start_of_action + 4)}; + FoxBytecodeFunctionHandle function_handle {.HashedName = function->Name->GetHash(), .BytecodeIndex = static_cast(start_of_function + 4)}; const size_t number_of_scope_var_handles = VarHandles.Size() - start_var_handle_count; printf("Number of var handles to remove: %zu\n", number_of_scope_var_handles); - ActionHandles.push_back(action_handle); + FunctionHandles.push_back(function_handle); --mScopeIndex; // Delete the variables on the stack for (int i = 0; i < number_of_scope_var_handles; i++) { - FxScriptBytecodeVarHandle* var = VarHandles.RemoveLast(); + FoxBytecodeVarHandle* var = VarHandles.RemoveLast(); assert(var->SizeOnStack == 4); mStackOffset -= var->SizeOnStack; } } -void FxScriptBCEmitter::EmitBlock(FxAstBlock* block) +void FoxBCEmitter::EmitBlock(FoxAstBlock* block) { RETURN_IF_NO_NODE(block); - for (FxAstNode* node : block->Statements) { + for (FoxAstNode* node : block->Statements) { Emit(node); } } -void FxScriptBCEmitter::PrintBytecode() +void FoxBCEmitter::PrintBytecode() { const size_t size = mBytecode.Size(); for (int i = 0; i < 25; i++) { @@ -2112,7 +2112,7 @@ void FxScriptBCEmitter::PrintBytecode() // Bytecode Printer ///////////////////////////////////// -uint16 FxScriptBCPrinter::Read16() +uint16 FoxBCPrinter::Read16() { uint8 lo = mBytecode[mBytecodeIndex++]; uint8 hi = mBytecode[mBytecodeIndex++]; @@ -2120,7 +2120,7 @@ uint16 FxScriptBCPrinter::Read16() return ((static_cast(lo) << 8) | hi); } -uint32 FxScriptBCPrinter::Read32() +uint32 FoxBCPrinter::Read32() { uint16 lo = Read16(); uint16 hi = Read16(); @@ -2130,22 +2130,22 @@ uint32 FxScriptBCPrinter::Read32() #define BC_PRINT_OP(fmt_, ...) snprintf(s, 128, fmt_, ##__VA_ARGS__) -void FxScriptBCPrinter::DoLoad(char* s, uint8 op_base, uint8 op_spec_raw) +void FoxBCPrinter::DoLoad(char* s, uint8 op_base, uint8 op_spec_raw) { uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); uint8 op_reg = (op_spec_raw & 0x0F); if (op_spec == OpSpecLoad_Int32) { int16 offset = Read16(); - BC_PRINT_OP("load32 %d, %s", offset, FxScriptBCEmitter::GetRegisterName(static_cast(op_reg))); + BC_PRINT_OP("load32 %d, %s", offset, FoxBCEmitter::GetRegisterName(static_cast(op_reg))); } else if (op_spec == OpSpecLoad_AbsoluteInt32) { uint32 offset = Read32(); - BC_PRINT_OP("load32a %u, %s", offset, FxScriptBCEmitter::GetRegisterName(static_cast(op_reg))); + BC_PRINT_OP("load32a %u, %s", offset, FoxBCEmitter::GetRegisterName(static_cast(op_reg))); } } -void FxScriptBCPrinter::DoPush(char* s, uint8 op_base, uint8 op_spec) +void FoxBCPrinter::DoPush(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == OpSpecPush_Int32) { uint32 value = Read32(); @@ -2153,32 +2153,32 @@ void FxScriptBCPrinter::DoPush(char* s, uint8 op_base, uint8 op_spec) } else if (op_spec == OpSpecPush_Reg32) { uint16 reg = Read16(); - BC_PRINT_OP("push32r %s", FxScriptBCEmitter::GetRegisterName(static_cast(reg))); + BC_PRINT_OP("push32r %s", FoxBCEmitter::GetRegisterName(static_cast(reg))); } } -void FxScriptBCPrinter::DoPop(char* s, uint8 op_base, uint8 op_spec_raw) +void FoxBCPrinter::DoPop(char* s, uint8 op_base, uint8 op_spec_raw) { uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); uint8 op_reg = (op_spec_raw & 0x0F); if (op_spec == OpSpecPush_Int32) { - BC_PRINT_OP("pop32 %s", FxScriptBCEmitter::GetRegisterName(static_cast(op_reg))); + BC_PRINT_OP("pop32 %s", FoxBCEmitter::GetRegisterName(static_cast(op_reg))); } } -void FxScriptBCPrinter::DoArith(char* s, uint8 op_base, uint8 op_spec) +void FoxBCPrinter::DoArith(char* s, uint8 op_base, uint8 op_spec) { uint8 a_reg = mBytecode[mBytecodeIndex++]; uint8 b_reg = mBytecode[mBytecodeIndex++]; if (op_spec == OpSpecArith_Add) { - BC_PRINT_OP("add32 %s, %s", FxScriptBCEmitter::GetRegisterName(static_cast(a_reg)), - FxScriptBCEmitter::GetRegisterName(static_cast(b_reg))); + BC_PRINT_OP("add32 %s, %s", FoxBCEmitter::GetRegisterName(static_cast(a_reg)), + FoxBCEmitter::GetRegisterName(static_cast(b_reg))); } } -void FxScriptBCPrinter::DoSave(char* s, uint8 op_base, uint8 op_spec) +void FoxBCPrinter::DoSave(char* s, uint8 op_base, uint8 op_spec) { // Save a imm32 into an offset in the stack if (op_spec == OpSpecSave_Int32) { @@ -2193,7 +2193,7 @@ void FxScriptBCPrinter::DoSave(char* s, uint8 op_base, uint8 op_spec) const int16 offset = Read16(); uint16 reg = Read16(); - BC_PRINT_OP("save32r %d, %s", offset, FxScriptBCEmitter::GetRegisterName(static_cast(reg))); + BC_PRINT_OP("save32r %d, %s", offset, FoxBCEmitter::GetRegisterName(static_cast(reg))); } else if (op_spec == OpSpecSave_AbsoluteInt32) { const uint32 offset = Read32(); @@ -2205,11 +2205,11 @@ void FxScriptBCPrinter::DoSave(char* s, uint8 op_base, uint8 op_spec) const uint32 offset = Read32(); uint16 reg = Read16(); - BC_PRINT_OP("save32ar %u, %s", offset, FxScriptBCEmitter::GetRegisterName(static_cast(reg))); + BC_PRINT_OP("save32ar %u, %s", offset, FoxBCEmitter::GetRegisterName(static_cast(reg))); } } -void FxScriptBCPrinter::DoJump(char* s, uint8 op_base, uint8 op_spec) +void FoxBCPrinter::DoJump(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == OpSpecJump_Relative) { uint16 offset = Read16(); @@ -2222,7 +2222,7 @@ void FxScriptBCPrinter::DoJump(char* s, uint8 op_base, uint8 op_spec) } else if (op_spec == OpSpecJump_AbsoluteReg32) { uint16 reg = Read16(); - BC_PRINT_OP("jmpar %s", FxScriptBCEmitter::GetRegisterName(static_cast(reg))); + BC_PRINT_OP("jmpar %s", FoxBCEmitter::GetRegisterName(static_cast(reg))); } else if (op_spec == OpSpecJump_CallAbsolute) { uint32 position = Read32(); @@ -2237,7 +2237,7 @@ void FxScriptBCPrinter::DoJump(char* s, uint8 op_base, uint8 op_spec) } } -void FxScriptBCPrinter::DoData(char* s, uint8 op_base, uint8 op_spec) +void FoxBCPrinter::DoData(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == OpSpecData_String) { uint16 length = Read16(); @@ -2260,7 +2260,7 @@ void FxScriptBCPrinter::DoData(char* s, uint8 op_base, uint8 op_spec) } } -void FxScriptBCPrinter::DoType(char* s, uint8 op_base, uint8 op_spec) +void FoxBCPrinter::DoType(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == OpSpecType_Int) { BC_PRINT_OP("typeint"); @@ -2270,26 +2270,26 @@ void FxScriptBCPrinter::DoType(char* s, uint8 op_base, uint8 op_spec) } } -void FxScriptBCPrinter::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) +void FoxBCPrinter::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) { uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); uint8 op_reg = (op_spec_raw & 0x0F); if (op_spec == OpSpecMove_Int32) { uint32 value = Read32(); - BC_PRINT_OP("move32 %s, %u\t", FxScriptBCEmitter::GetRegisterName(static_cast(op_reg)), value); + BC_PRINT_OP("move32 %s, %u\t", FoxBCEmitter::GetRegisterName(static_cast(op_reg)), value); } } -void FxScriptBCPrinter::Print() +void FoxBCPrinter::Print() { while (mBytecodeIndex < mBytecode.Size()) { PrintOp(); } } -void FxScriptBCPrinter::PrintOp() +void FoxBCPrinter::PrintOp() { uint32 bc_index = mBytecodeIndex; @@ -2340,7 +2340,7 @@ void FxScriptBCPrinter::PrintOp() // Bytecode VM /////////////////////////////////////////// -void FxScriptVM::PrintRegisters() +void FoxVM::PrintRegisters() { printf("\n=== Register Dump ===\n\n"); printf("X0=%u\tX1=%u\tX2=%u\tX3=%u\n", Registers[FX_REG_X0], Registers[FX_REG_X1], Registers[FX_REG_X2], Registers[FX_REG_X3]); @@ -2350,7 +2350,7 @@ void FxScriptVM::PrintRegisters() printf("\n=====================\n\n"); } -uint16 FxScriptVM::Read16() +uint16 FoxVM::Read16() { uint8 lo = mBytecode[mPC++]; uint8 hi = mBytecode[mPC++]; @@ -2358,7 +2358,7 @@ uint16 FxScriptVM::Read16() return ((static_cast(lo) << 8) | hi); } -uint32 FxScriptVM::Read32() +uint32 FoxVM::Read32() { uint16 lo = Read16(); uint16 hi = Read16(); @@ -2366,7 +2366,7 @@ uint32 FxScriptVM::Read32() return ((static_cast(lo) << 16) | hi); } -void FxScriptVM::Push16(uint16 value) +void FoxVM::Push16(uint16 value) { uint16* dptr = reinterpret_cast(Stack + Registers[FX_REG_SP]); (*dptr) = value; @@ -2374,7 +2374,7 @@ void FxScriptVM::Push16(uint16 value) Registers[FX_REG_SP] += sizeof(uint16); } -void FxScriptVM::Push32(uint32 value) +void FoxVM::Push32(uint32 value) { uint32* dptr = reinterpret_cast(Stack + Registers[FX_REG_SP]); (*dptr) = value; @@ -2382,7 +2382,7 @@ void FxScriptVM::Push32(uint32 value) Registers[FX_REG_SP] += sizeof(uint32); } -uint32 FxScriptVM::Pop32() +uint32 FoxVM::Pop32() { if (Registers[FX_REG_SP] == 0) { printf("ERR\n"); @@ -2395,19 +2395,19 @@ uint32 FxScriptVM::Pop32() } -FxScriptVMCallFrame& FxScriptVM::PushCallFrame() +FoxVMCallFrame& FoxVM::PushCallFrame() { mIsInCallFrame = true; - FxScriptVMCallFrame& start_frame = mCallFrames[mCallFrameIndex++]; + FoxVMCallFrame& start_frame = mCallFrames[mCallFrameIndex++]; start_frame.StartStackIndex = Registers[FX_REG_SP]; return start_frame; } -void FxScriptVM::PopCallFrame() +void FoxVM::PopCallFrame() { - FxScriptVMCallFrame* frame = GetCurrentCallFrame(); + FoxVMCallFrame* frame = GetCurrentCallFrame(); if (!frame) { FX_BREAKPOINT; } @@ -2423,7 +2423,7 @@ void FxScriptVM::PopCallFrame() } } -FxScriptVMCallFrame* FxScriptVM::GetCurrentCallFrame() +FoxVMCallFrame* FoxVM::GetCurrentCallFrame() { if (!mIsInCallFrame || mCallFrameIndex < 1) { return nullptr; @@ -2432,9 +2432,9 @@ FxScriptVMCallFrame* FxScriptVM::GetCurrentCallFrame() return &mCallFrames[mCallFrameIndex - 1]; } -FxScriptExternalFunc* FxScriptVM::FindExternalAction(FxHash hashed_name) +FoxExternalFunc* FoxVM::FindExternalFunction(FoxHash hashed_name) { - for (FxScriptExternalFunc& func : mExternalFuncs) { + for (FoxExternalFunc& func : mExternalFuncs) { if (func.HashedName == hashed_name) { return &func; } @@ -2442,7 +2442,7 @@ FxScriptExternalFunc* FxScriptVM::FindExternalAction(FxHash hashed_name) return nullptr; } -void FxScriptVM::ExecuteOp() +void FoxVM::ExecuteOp() { uint16 op_full = Read16(); @@ -2480,7 +2480,7 @@ void FxScriptVM::ExecuteOp() } } -void FxScriptVM::DoLoad(uint8 op_base, uint8 op_spec_raw) +void FoxVM::DoLoad(uint8 op_base, uint8 op_spec_raw) { uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); uint8 op_reg = (op_spec_raw & 0x0F); @@ -2503,15 +2503,15 @@ void FxScriptVM::DoLoad(uint8 op_base, uint8 op_spec_raw) } } -void FxScriptVM::DoPush(uint8 op_base, uint8 op_spec) +void FoxVM::DoPush(uint8 op_base, uint8 op_spec) { if (mIsInParams) { - if (mCurrentType != FxScriptValue::NONETYPE) { + if (mCurrentType != FoxValue::NONETYPE) { mPushedTypes.Insert(mCurrentType); - mCurrentType = FxScriptValue::NONETYPE; + mCurrentType = FoxValue::NONETYPE; } else { - mPushedTypes.Insert(FxScriptValue::INT); + mPushedTypes.Insert(FoxValue::INT); } } @@ -2525,7 +2525,7 @@ void FxScriptVM::DoPush(uint8 op_base, uint8 op_spec) } } -void FxScriptVM::DoPop(uint8 op_base, uint8 op_spec_raw) +void FoxVM::DoPop(uint8 op_base, uint8 op_spec_raw) { uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); uint8 op_reg = (op_spec_raw & 0x0F); @@ -2541,7 +2541,7 @@ void FxScriptVM::DoPop(uint8 op_base, uint8 op_spec_raw) } } -void FxScriptVM::DoArith(uint8 op_base, uint8 op_spec) +void FoxVM::DoArith(uint8 op_base, uint8 op_spec) { uint8 a_reg = mBytecode[mPC++]; uint8 b_reg = mBytecode[mPC++]; @@ -2551,7 +2551,7 @@ void FxScriptVM::DoArith(uint8 op_base, uint8 op_spec) } } -void FxScriptVM::DoSave(uint8 op_base, uint8 op_spec) +void FoxVM::DoSave(uint8 op_base, uint8 op_spec) { uint32 offset; @@ -2587,7 +2587,7 @@ void FxScriptVM::DoSave(uint8 op_base, uint8 op_spec) } } -void FxScriptVM::DoJump(uint8 op_base, uint8 op_spec) +void FoxVM::DoJump(uint8 op_base, uint8 op_spec) { if (op_spec == OpSpecJump_Relative) { uint16 offset = Read16(); @@ -2614,7 +2614,7 @@ void FxScriptVM::DoJump(uint8 op_base, uint8 op_spec) PushCallFrame(); - // Jump to the action address + // Jump to the function address mPC = call_address; } else if (op_spec == OpSpecJump_ReturnToCaller) { @@ -2632,14 +2632,14 @@ void FxScriptVM::DoJump(uint8 op_base, uint8 op_spec) else if (op_spec == OpSpecJump_CallExternal) { uint32 hashed_name = Read32(); - FxScriptExternalFunc* external_func = FindExternalAction(hashed_name); + FoxExternalFunc* external_func = FindExternalFunction(hashed_name); if (!external_func) { printf("!!! Could not find external function in VM!\n"); return; } - std::vector params; + std::vector params; params.reserve(external_func->ParameterTypes.size()); uint32 num_params = mPushedTypes.Size(); @@ -2647,16 +2647,16 @@ void FxScriptVM::DoJump(uint8 op_base, uint8 op_spec) printf("Num Params: %u\n", num_params); for (int i = 0; i < num_params; i++) { - FxScriptValue::ValueType param_type = mPushedTypes.GetLast(); + FoxValue::ValueType param_type = mPushedTypes.GetLast(); - FxScriptValue value; + FoxValue value; value.Type = param_type; - if (param_type == FxScriptValue::INT) { + if (param_type == FoxValue::INT) { value.ValueInt = Pop32(); value.Type = param_type; } - else if (param_type == FxScriptValue::STRING) { + else if (param_type == FoxValue::STRING) { uint32 string_location = Pop32(); uint8* str_base_ptr = &mBytecode[string_location]; // uint16 str_length = *((uint16*)str_base_ptr); @@ -2675,12 +2675,12 @@ void FxScriptVM::DoJump(uint8 op_base, uint8 op_spec) mPushedTypes.Clear(); mIsInParams = false; - FxScriptValue return_value {}; + FoxValue return_value {}; external_func->Function(this, params, &return_value); } } -void FxScriptVM::DoData(uint8 op_base, uint8 op_spec) +void FoxVM::DoData(uint8 op_base, uint8 op_spec) { if (op_spec == OpSpecData_String) { uint16 length = Read16(); @@ -2689,26 +2689,26 @@ void FxScriptVM::DoData(uint8 op_base, uint8 op_spec) else if (op_spec == OpSpecData_ParamsStart) { mIsInParams = true; - // Push the current return address pointer. This is so nested action calls can correctly navigate back + // Push the current return address pointer. This is so nested function calls can correctly navigate back // to the caller. // Push32(Registers[FX_REG_RA]); } } -void FxScriptVM::DoType(uint8 op_base, uint8 op_spec) +void FoxVM::DoType(uint8 op_base, uint8 op_spec) { if (op_spec == OpSpecType_Int) { - mCurrentType = FxScriptValue::INT; + mCurrentType = FoxValue::INT; } else if (op_spec == OpSpecType_String) { - mCurrentType = FxScriptValue::STRING; + mCurrentType = FoxValue::STRING; } } -void FxScriptVM::DoMove(uint8 op_base, uint8 op_spec_raw) +void FoxVM::DoMove(uint8 op_base, uint8 op_spec_raw) { uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); - FxScriptRegister op_reg = static_cast(op_spec_raw & 0x0F); + FoxBCRegister op_reg = static_cast(op_spec_raw & 0x0F); if (op_spec == OpSpecMove_Int32) { int32 value = Read32(); @@ -2721,7 +2721,7 @@ void FxScriptVM::DoMove(uint8 op_base, uint8 op_spec_raw) // Script Bytecode to x86 Transpiler ////////////////////////////////////////////////// -uint16 FxScriptTranspilerX86::Read16() +uint16 FoxTranspilerX86::Read16() { uint8 lo = mBytecode[mBytecodeIndex++]; uint8 hi = mBytecode[mBytecodeIndex++]; @@ -2729,7 +2729,7 @@ uint16 FxScriptTranspilerX86::Read16() return ((static_cast(lo) << 8) | hi); } -uint32 FxScriptTranspilerX86::Read32() +uint32 FoxTranspilerX86::Read32() { uint16 lo = Read16(); uint16 hi = Read16(); @@ -2737,7 +2737,7 @@ uint32 FxScriptTranspilerX86::Read32() return ((static_cast(lo) << 16) | hi); } -static const char* GetX86Register(FxScriptRegister reg) +static const char* GetX86Register(FoxBCRegister reg) { switch (reg) { case FX_REG_X0: @@ -2761,7 +2761,7 @@ static const char* GetX86Register(FxScriptRegister reg) // #define BC_PRINT_OP(fmt_, ...) snprintf(s, 128, fmt_, ##__VA_ARGS__) -void FxScriptTranspilerX86::DoLoad(char* s, uint8 op_base, uint8 op_spec_raw) +void FoxTranspilerX86::DoLoad(char* s, uint8 op_base, uint8 op_spec_raw) { uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); uint8 op_reg = (op_spec_raw & 0x0F); @@ -2770,16 +2770,16 @@ void FxScriptTranspilerX86::DoLoad(char* s, uint8 op_base, uint8 op_spec_raw) int16 offset = Read16(); // load32 [off32] [%r32] offset += 8; - StrOut("mov %s, [ebp %c %d]", GetX86Register(static_cast(op_reg)), (offset <= 0 ? '+' : '-'), abs(offset)); + StrOut("mov %s, [ebp %c %d]", GetX86Register(static_cast(op_reg)), (offset <= 0 ? '+' : '-'), abs(offset)); } else if (op_spec == OpSpecLoad_AbsoluteInt32) { uint32 offset = Read32(); - // StrOut("load32a %u, %s", offset, GetX86Register(static_cast(op_reg))); - StrOut("mov %s, [esi + %u]", GetX86Register(static_cast(op_reg)), offset); + // StrOut("load32a %u, %s", offset, GetX86Register(static_cast(op_reg))); + StrOut("mov %s, [esi + %u]", GetX86Register(static_cast(op_reg)), offset); } } -void FxScriptTranspilerX86::DoPush(char* s, uint8 op_base, uint8 op_spec) +void FoxTranspilerX86::DoPush(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == OpSpecPush_Int32) { uint32 value = Read32(); @@ -2789,37 +2789,37 @@ void FxScriptTranspilerX86::DoPush(char* s, uint8 op_base, uint8 op_spec) else if (op_spec == OpSpecPush_Reg32) { uint16 reg = Read16(); // push32r [%reg32] - StrOut("push %s", GetX86Register(static_cast(reg))); + StrOut("push %s", GetX86Register(static_cast(reg))); } - if (mIsInAction) { - mSizePushedInAction += 4; + if (mIsInFunction) { + mSizePushedInFunction += 4; } } -void FxScriptTranspilerX86::DoPop(char* s, uint8 op_base, uint8 op_spec_raw) +void FoxTranspilerX86::DoPop(char* s, uint8 op_base, uint8 op_spec_raw) { uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); uint8 op_reg = (op_spec_raw & 0x0F); - if (op_spec == OpSpecPush_Int32) { + if (op_spec == OpSpecPop_Int32) { // pop32 [%reg32] - StrOut("pop %s", GetX86Register(static_cast(op_reg))); + StrOut("pop %s", GetX86Register(static_cast(op_reg))); } } -void FxScriptTranspilerX86::DoArith(char* s, uint8 op_base, uint8 op_spec) +void FoxTranspilerX86::DoArith(char* s, uint8 op_base, uint8 op_spec) { uint8 a_reg = mBytecode[mBytecodeIndex++]; uint8 b_reg = mBytecode[mBytecodeIndex++]; if (op_spec == OpSpecArith_Add) { // add32 [%reg32] [%reg32] - StrOut("add %s, %s", GetX86Register(static_cast(a_reg)), GetX86Register(static_cast(b_reg))); + StrOut("add %s, %s", GetX86Register(static_cast(a_reg)), GetX86Register(static_cast(b_reg))); } } -void FxScriptTranspilerX86::DoSave(char* s, uint8 op_base, uint8 op_spec) +void FoxTranspilerX86::DoSave(char* s, uint8 op_base, uint8 op_spec) { // Save a imm32 into an offset in the stack if (op_spec == OpSpecSave_Int32) { @@ -2837,8 +2837,8 @@ void FxScriptTranspilerX86::DoSave(char* s, uint8 op_base, uint8 op_spec) offset += 8; - StrOut("mov [ebp %c %d], %s", (offset <= 0 ? '+' : '-'), abs(offset), GetX86Register(static_cast(reg))); - // BC_PRINT_OP("save32r %d, %s", offset, GetX86Register(static_cast(reg))); + StrOut("mov [ebp %c %d], %s", (offset <= 0 ? '+' : '-'), abs(offset), GetX86Register(static_cast(reg))); + // BC_PRINT_OP("save32r %d, %s", offset, GetX86Register(static_cast(reg))); } else if (op_spec == OpSpecSave_AbsoluteInt32) { const uint32 offset = Read32(); @@ -2851,17 +2851,17 @@ void FxScriptTranspilerX86::DoSave(char* s, uint8 op_base, uint8 op_spec) const uint32 offset = Read32(); uint16 reg = Read16(); - // StrOut("save32ar %u, %s", offset, GetX86Register(static_cast(reg))); - StrOut("mov [esi %c %d], %s", (offset <= 0 ? '+' : '-'), offset, GetX86Register(static_cast(reg))); + // StrOut("save32ar %u, %s", offset, GetX86Register(static_cast(reg))); + StrOut("mov [esi %c %d], %s", (offset <= 0 ? '+' : '-'), offset, GetX86Register(static_cast(reg))); } } -void FxScriptTranspilerX86::DoJump(char* s, uint8 op_base, uint8 op_spec) +void FoxTranspilerX86::DoJump(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == OpSpecJump_Relative) { uint16 offset = Read16(); - mIsInAction = true; + mIsInFunction = true; StrOut("jmp _A_%u", mBytecodeIndex + offset); @@ -2884,7 +2884,7 @@ void FxScriptTranspilerX86::DoJump(char* s, uint8 op_base, uint8 op_spec) } else if (op_spec == OpSpecJump_AbsoluteReg32) { uint16 reg = Read16(); - StrOut("jmpar %s", GetX86Register(static_cast(reg))); + StrOut("jmpar %s", GetX86Register(static_cast(reg))); } else if (op_spec == OpSpecJump_CallAbsolute) { uint32 position = Read32(); @@ -2892,9 +2892,9 @@ void FxScriptTranspilerX86::DoJump(char* s, uint8 op_base, uint8 op_spec) StrOut("call _L_%u", position); } else if (op_spec == OpSpecJump_ReturnToCaller) { - StrOut("add esp, %u", mSizePushedInAction); - mSizePushedInAction = 0; - mIsInAction = false; + StrOut("add esp, %u", mSizePushedInFunction); + mSizePushedInFunction = 0; + mIsInFunction = false; StrOut(""); StrOut("push esi ; push return address"); @@ -2914,7 +2914,7 @@ void FxScriptTranspilerX86::DoJump(char* s, uint8 op_base, uint8 op_spec) } } -void FxScriptTranspilerX86::DoData(char* s, uint8 op_base, uint8 op_spec) +void FoxTranspilerX86::DoData(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == OpSpecData_String) { uint16 length = Read16(); @@ -2938,7 +2938,7 @@ void FxScriptTranspilerX86::DoData(char* s, uint8 op_base, uint8 op_spec) } } -void FxScriptTranspilerX86::DoType(char* s, uint8 op_base, uint8 op_spec) +void FoxTranspilerX86::DoType(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == OpSpecType_Int) { // BC_PRINT_OP("typeint"); @@ -2948,20 +2948,20 @@ void FxScriptTranspilerX86::DoType(char* s, uint8 op_base, uint8 op_spec) } } -void FxScriptTranspilerX86::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) +void FoxTranspilerX86::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) { uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); - FxScriptRegister op_reg = static_cast(op_spec_raw & 0x0F); + FoxBCRegister op_reg = static_cast(op_spec_raw & 0x0F); if (op_spec == OpSpecMove_Int32) { int32 value = Read32(); - // StrOut("move32 %s, %u", FxScriptBCEmitter::GetRegisterName(op_reg), value); + // StrOut("move32 %s, %u", FoxBCEmitter::GetRegisterName(op_reg), value); StrOut("mov %s, %d", GetX86Register(op_reg), value); } } -void FxScriptTranspilerX86::Print() +void FoxTranspilerX86::Print() { // Print header StrOut("section .text"); @@ -2982,7 +2982,7 @@ void FxScriptTranspilerX86::Print() #include -void FxScriptTranspilerX86::StrOut(const char* fmt, ...) +void FoxTranspilerX86::StrOut(const char* fmt, ...) { for (int i = 0; i < mTextIndent; i++) { putchar('\t'); @@ -2996,7 +2996,7 @@ void FxScriptTranspilerX86::StrOut(const char* fmt, ...) puts(""); } -void FxScriptTranspilerX86::PrintOp() +void FoxTranspilerX86::PrintOp() { // uint32 bc_index = mBytecodeIndex; @@ -3040,11 +3040,13 @@ void FxScriptTranspilerX86::PrintOp() } -#pragma region IrEmitter +/////////////////////////////////////////////// +// IR Asm Emitter +/////////////////////////////////////////////// -#include "FxScriptBytecode.hpp" +#pragma region IrEmitter -void FxScriptIREmitter::BeginEmitting(FxAstNode* node) +void FoxIREmitter::BeginEmitting(FoxAstNode* node) { mStackSize = 1024; @@ -3071,44 +3073,49 @@ void FxScriptIREmitter::BeginEmitting(FxAstNode* node) return (value_); \ } -void FxScriptIREmitter::Emit(FxAstNode* node) +void FoxIREmitter::Emit(FoxAstNode* node) { RETURN_IF_NO_NODE(node); if (node->NodeType == FX_AST_BLOCK) { - return EmitBlock(reinterpret_cast(node)); + return EmitBlock(reinterpret_cast(node)); } else if (node->NodeType == FX_AST_ACTIONDECL) { - return EmitAction(reinterpret_cast(node)); + return EmitFunction(reinterpret_cast(node)); } else if (node->NodeType == FX_AST_ACTIONCALL) { - return DoActionCall(reinterpret_cast(node)); + return DoFunctionCall(reinterpret_cast(node)); } else if (node->NodeType == FX_AST_ASSIGN) { - return EmitAssign(reinterpret_cast(node)); + return EmitAssign(reinterpret_cast(node)); } else if (node->NodeType == FX_AST_VARDECL) { - DoVarDeclare(reinterpret_cast(node)); + DoVarDeclare(reinterpret_cast(node)); return; } else if (node->NodeType == FX_AST_RETURN) { - constexpr FxHash return_val_hash = FxHashStr(FX_SCRIPT_VAR_RETURN_VAL); + constexpr FoxHash return_val_hash = FoxHashStr(FX_SCRIPT_VAR_RETURN_VAL); + + FoxBytecodeVarHandle* return_var = FindVarHandle(return_val_hash); - FxScriptBytecodeVarHandle* return_var = FindVarHandle(return_val_hash); + FoxIRRegister result_register = FindFreeReg32(); + MARK_REGISTER_USED(result_register); if (return_var) { - DoLoad(return_var->Offset, FX_REG_XR); + DoLoad(return_var->Offset, result_register); } + MARK_REGISTER_FREE(result_register); + EmitJumpReturnToCaller(); return; } } -FxScriptBytecodeVarHandle* FxScriptIREmitter::FindVarHandle(FxHash hashed_name) +FoxBytecodeVarHandle* FoxIREmitter::FindVarHandle(FoxHash hashed_name) { - for (FxScriptBytecodeVarHandle& handle : VarHandles) { + for (FoxBytecodeVarHandle& handle : VarHandles) { if (handle.HashedName == hashed_name) { return &handle; } @@ -3116,9 +3123,9 @@ FxScriptBytecodeVarHandle* FxScriptIREmitter::FindVarHandle(FxHash hashed_name) return nullptr; } -FxScriptBytecodeActionHandle* FxScriptIREmitter::FindActionHandle(FxHash hashed_name) +FoxBytecodeFunctionHandle* FoxIREmitter::FindFunctionHandle(FoxHash hashed_name) { - for (FxScriptBytecodeActionHandle& handle : ActionHandles) { + for (FoxBytecodeFunctionHandle& handle : FunctionHandles) { if (handle.HashedName == hashed_name) { return &handle; } @@ -3127,118 +3134,78 @@ FxScriptBytecodeActionHandle* FxScriptIREmitter::FindActionHandle(FxHash hashed_ } -FxScriptRegister FxScriptIREmitter::FindFreeRegister() +FoxIRRegister FoxIREmitter::FindFreeReg32() { - uint16 gp_r = 0x01; + for (int register_index = FX_IR_GW0; register_index <= FX_IR_GW3; register_index++) { + uint32 gp_r = (1 << register_index); - const uint16 num_gp_regs = FX_REG_X3; - - for (int i = 0; i < num_gp_regs; i++) { if (!(mRegsInUse & gp_r)) { - // We are starting on 0x01, so register index should be N + 1 - const int register_index = i + 1; - - return static_cast(register_index); + return static_cast(register_index); } - - gp_r <<= 1; } - return FxScriptRegister::FX_REG_NONE; + return FX_IR_GW3; } -const char* FxScriptIREmitter::GetRegisterName(FxScriptRegister reg) +FoxIRRegister FoxIREmitter::FindFreeReg64() { - switch (reg) { - case FX_REG_NONE: - return "NONE"; - case FX_REG_X0: - return "X0"; - case FX_REG_X1: - return "X1"; - case FX_REG_X2: - return "X2"; - case FX_REG_X3: - return "X3"; - case FX_REG_RA: - return "RA"; - case FX_REG_XR: - return "XR"; - case FX_REG_SP: - return "SP"; - default:; - }; - - return "NONE"; -} + for (int register_index = FX_IR_GX0; register_index <= FX_IR_GX3; register_index++) { + uint32 gp_r = (1 << register_index); -FxScriptRegister FxScriptIREmitter::RegFlagToReg(FxScriptRegisterFlag reg_flag) -{ - switch (reg_flag) { - case FX_REGFLAG_NONE: - return FX_REG_NONE; - case FX_REGFLAG_X0: - return FX_REG_X0; - case FX_REGFLAG_X1: - return FX_REG_X1; - case FX_REGFLAG_X2: - return FX_REG_X2; - case FX_REGFLAG_X3: - return FX_REG_X3; - case FX_REGFLAG_RA: - return FX_REG_RA; - case FX_REGFLAG_XR: - return FX_REG_XR; + if (!(mRegsInUse & gp_r)) { + return static_cast(register_index); + } } - return FX_REG_NONE; + return FX_IR_GX3; } -FxScriptRegisterFlag FxScriptIREmitter::RegToRegFlag(FxScriptRegister reg) +const char* FoxIREmitter::GetRegisterName(FoxIRRegister reg) { switch (reg) { - case FX_REG_NONE: - return FX_REGFLAG_NONE; - case FX_REG_X0: - return FX_REGFLAG_X0; - case FX_REG_X1: - return FX_REGFLAG_X1; - case FX_REG_X2: - return FX_REGFLAG_X2; - case FX_REG_X3: - return FX_REGFLAG_X3; - case FX_REG_RA: - return FX_REGFLAG_RA; - case FX_REG_XR: - return FX_REGFLAG_XR; - case FX_REG_SP: - return FX_REGFLAG_NONE; + case FX_IR_GW0: + return "GW0"; + case FX_IR_GW1: + return "GW1"; + case FX_IR_GW2: + return "GW2"; + case FX_IR_GW3: + return "GW3"; + case FX_IR_GX0: + return "GX0"; + case FX_IR_GX1: + return "GX1"; + case FX_IR_GX2: + return "GX2"; + case FX_IR_GX3: + return "GX3"; + case FX_IR_SP: + return "SP"; default:; - } + }; - return FX_REGFLAG_NONE; + return "NONE"; } - -void FxScriptIREmitter::Write16(uint16 value) +void FoxIREmitter::Write16(uint16 value) { mBytecode.Insert(static_cast(value >> 8)); mBytecode.Insert(static_cast(value)); } -void FxScriptIREmitter::Write32(uint32 value) +void FoxIREmitter::Write32(uint32 value) { Write16(static_cast(value >> 16)); Write16(static_cast(value)); } -void FxScriptIREmitter::WriteOp(uint8 op_base, uint8 op_spec) +void FoxIREmitter::WriteOp(uint8 op_base, uint8 op_spec) { mBytecode.Insert(op_base); mBytecode.Insert(op_spec); } -using IRRhsMode = FxScriptIREmitter::RhsMode; +using IRRhsMode = FoxIREmitter::RhsMode; #define MARK_REGISTER_USED(regn_) \ { \ @@ -3249,20 +3216,19 @@ using IRRhsMode = FxScriptIREmitter::RhsMode; MarkRegisterFree(regn_); \ } -void FxScriptIREmitter::MarkRegisterUsed(FxScriptRegister reg) +void FoxIREmitter::MarkRegisterUsed(FoxIRRegister reg) { - FxScriptRegisterFlag rflag = RegToRegFlag(reg); - mRegsInUse = static_cast(uint16(mRegsInUse) | uint16(rflag)); + uint16 register_flag = (1 << reg); + mRegsInUse = static_cast(uint16(mRegsInUse) | register_flag); } -void FxScriptIREmitter::MarkRegisterFree(FxScriptRegister reg) +void FoxIREmitter::MarkRegisterFree(FoxIRRegister reg) { - FxScriptRegisterFlag rflag = RegToRegFlag(reg); - - mRegsInUse = static_cast(uint16(mRegsInUse) & (~uint16(rflag))); + uint16 register_flag = (1 << reg); + mRegsInUse = static_cast(uint16(mRegsInUse) & (~register_flag)); } -void FxScriptIREmitter::EmitSave32(int16 offset, uint32 value) +void FoxIREmitter::EmitSave32(int16 offset, uint32 value) { // SAVE32 [i16 offset] [i32] WriteOp(IrBase_Save, IrSpecSave_Int32); @@ -3271,7 +3237,7 @@ void FxScriptIREmitter::EmitSave32(int16 offset, uint32 value) Write32(value); } -void FxScriptIREmitter::EmitSaveReg32(int16 offset, FxScriptRegister reg) +void FoxIREmitter::EmitSaveReg32(int16 offset, FoxIRRegister reg) { // SAVE32r [i16 offset] [%r32] WriteOp(IrBase_Save, IrSpecSave_Reg32); @@ -3281,7 +3247,7 @@ void FxScriptIREmitter::EmitSaveReg32(int16 offset, FxScriptRegister reg) } -void FxScriptIREmitter::EmitSaveAbsolute32(uint32 position, uint32 value) +void FoxIREmitter::EmitSaveAbsolute32(uint32 position, uint32 value) { // SAVE32a [i32 offset] [i32] WriteOp(IrBase_Save, IrSpecSave_AbsoluteInt32); @@ -3290,7 +3256,7 @@ void FxScriptIREmitter::EmitSaveAbsolute32(uint32 position, uint32 value) Write32(value); } -void FxScriptIREmitter::EmitSaveAbsoluteReg32(uint32 position, FxScriptRegister reg) +void FoxIREmitter::EmitSaveAbsoluteReg32(uint32 position, FoxIRRegister reg) { // SAVE32r [i32 offset] [%r32] WriteOp(IrBase_Save, IrSpecSave_AbsoluteReg32); @@ -3299,7 +3265,7 @@ void FxScriptIREmitter::EmitSaveAbsoluteReg32(uint32 position, FxScriptRegister Write16(reg); } -void FxScriptIREmitter::EmitPush32(uint32 value) +void FoxIREmitter::EmitPush32(uint32 value) { // PUSH32 [i32] WriteOp(IrBase_Push, IrSpecPush_Int32); @@ -3308,7 +3274,7 @@ void FxScriptIREmitter::EmitPush32(uint32 value) mStackOffset += 4; } -void FxScriptIREmitter::EmitPush32r(FxScriptRegister reg) +void FoxIREmitter::EmitPush32r(FoxIRRegister reg) { // PUSH32r [%r32] WriteOp(IrBase_Push, IrSpecPush_Reg32); @@ -3317,8 +3283,18 @@ void FxScriptIREmitter::EmitPush32r(FxScriptRegister reg) mStackOffset += 4; } +void FoxIREmitter::EmitStackAlloc(uint16 size) +{ + // SALLOC [u16] + + WriteOp(IrBase_Push, IrSpecPush_StackAlloc); + Write16(size); + + mStackOffset += size; +} + -void FxScriptIREmitter::EmitPop32(FxScriptRegister output_reg) +void FoxIREmitter::EmitPop32(FoxIRRegister output_reg) { // POP32 [%r32] WriteOp(IrBase_Pop, (IrSpecPop_Int32 << 4) | (output_reg & 0x0F)); @@ -3326,80 +3302,101 @@ void FxScriptIREmitter::EmitPop32(FxScriptRegister output_reg) mStackOffset -= 4; } -void FxScriptIREmitter::EmitLoad32(int offset, FxScriptRegister output_reg) +void FoxIREmitter::EmitLoad32(int offset, FoxIRRegister output_reg) { // LOAD [i16] [%r32] WriteOp(IrBase_Load, (IrSpecLoad_Int32 << 4) | (output_reg & 0x0F)); Write16(static_cast(offset)); } -void FxScriptIREmitter::EmitLoadAbsolute32(uint32 position, FxScriptRegister output_reg) +void FoxIREmitter::EmitLoadAbsolute32(uint32 position, FoxIRRegister output_reg) { // LOADA [i32] [%r32] WriteOp(IrBase_Load, (IrSpecLoad_AbsoluteInt32 << 4) | (output_reg & 0x0F)); Write32(position); } -void FxScriptIREmitter::EmitJumpRelative(uint16 offset) +void FoxIREmitter::EmitJumpRelative(uint16 offset) { WriteOp(IrBase_Jump, IrSpecJump_Relative); Write16(offset); } -void FxScriptIREmitter::EmitJumpAbsolute(uint32 position) +void FoxIREmitter::EmitJumpAbsolute(uint32 position) { WriteOp(IrBase_Jump, IrSpecJump_Absolute); Write32(position); } -void FxScriptIREmitter::EmitJumpAbsoluteReg32(FxScriptRegister reg) +void FoxIREmitter::EmitJumpAbsoluteReg32(FoxIRRegister reg) { WriteOp(IrBase_Jump, IrSpecJump_AbsoluteReg32); Write16(reg); } -void FxScriptIREmitter::EmitJumpCallAbsolute(uint32 position) +void FoxIREmitter::EmitJumpCallAbsolute(uint32 position) { WriteOp(IrBase_Jump, IrSpecJump_CallAbsolute); Write32(position); } -void FxScriptIREmitter::EmitJumpCallExternal(FxHash hashed_name) +void FoxIREmitter::EmitJumpCallExternal(FoxHash hashed_name) { WriteOp(IrBase_Jump, IrSpecJump_CallExternal); Write32(hashed_name); } -void FxScriptIREmitter::EmitJumpReturnToCaller() +void FoxIREmitter::EmitJumpReturnToCaller() { WriteOp(IrBase_Jump, IrSpecJump_ReturnToCaller); } -void FxScriptIREmitter::EmitMoveInt32(FxScriptRegister reg, uint32 value) +void FoxIREmitter::EmitMoveInt32(FoxIRRegister reg, uint32 value) { WriteOp(IrBase_Move, (IrSpecMove_Int32 << 4) | (reg & 0x0F)); Write32(value); } -void FxScriptIREmitter::EmitParamsStart() +void FoxIREmitter::EmitVariableSetInt32(uint16 var_index, int32 value) +{ + WriteOp(IrBase_Variable, IrSpecVariable_Set_Int32); + Write16(var_index); + Write32(value); +} + +void FoxIREmitter::EmitVariableSetReg32(uint16 var_index, FoxIRRegister reg) +{ + WriteOp(IrBase_Variable, IrSpecVariable_Set_Reg32); + Write16(var_index); + Write16(reg); +} + +void FoxIREmitter::EmitVariableGetInt32(uint16 var_index, FoxIRRegister dest_reg) +{ + WriteOp(IrBase_Variable, IrSpecVariable_Get_Int32); + Write16(var_index); + Write16(dest_reg); +} + +void FoxIREmitter::EmitParamsStart() { - WriteOp(IrBase_Data, IrSpecData_ParamsStart); + WriteOp(IrBase_Marker, IrSpecMarker_ParamsBegin); } -void FxScriptIREmitter::EmitType(FxScriptValue::ValueType type) +void FoxIREmitter::EmitType(FoxValue::ValueType type) { IrSpecType op_type = IrSpecType_Int; - if (type == FxScriptValue::STRING) { + if (type == FoxValue::STRING) { op_type = IrSpecType_String; } WriteOp(IrBase_Type, op_type); } -uint32 FxScriptIREmitter::EmitDataString(char* str, uint16 length) +uint32 FoxIREmitter::EmitDataString(char* str, uint16 length) { WriteOp(IrBase_Data, IrSpecData_String); @@ -3429,20 +3426,20 @@ uint32 FxScriptIREmitter::EmitDataString(char* str, uint16 length) } -FxScriptRegister FxScriptIREmitter::EmitBinop(FxAstBinop* binop, FxScriptBytecodeVarHandle* handle) +FoxIRRegister FoxIREmitter::EmitBinop(FoxAstBinop* binop, FoxBytecodeVarHandle* handle) { bool will_preserve_lhs = false; // Load the A and B values into the registers - FxScriptRegister a_reg = EmitRhs(binop->Left, RhsMode::RHS_FETCH_TO_REGISTER, handle); + FoxIRRegister a_reg = EmitRhs(binop->Left, RhsMode::RHS_FETCH_TO_REGISTER, handle); - // Since there is a chance that this register will be clobbered (by binop, action call, etc), we will + // Since there is a chance that this register will be clobbered (by binop, function call, etc), we will // push the value of the register here and return it after processing the RHS if (binop->Right->NodeType != FX_AST_LITERAL) { will_preserve_lhs = true; EmitPush32r(a_reg); } - FxScriptRegister b_reg = EmitRhs(binop->Right, RhsMode::RHS_FETCH_TO_REGISTER, handle); + FoxIRRegister b_reg = EmitRhs(binop->Right, RhsMode::RHS_FETCH_TO_REGISTER, handle); // Retrieve the previous LHS if (will_preserve_lhs) { @@ -3457,15 +3454,15 @@ FxScriptRegister FxScriptIREmitter::EmitBinop(FxAstBinop* binop, FxScriptBytecod } // We no longer need the lhs or rhs registers, free em - MARK_REGISTER_FREE(a_reg); + // MARK_REGISTER_FREE(a_reg); MARK_REGISTER_FREE(b_reg); - return FX_REG_XR; + return a_reg; } -FxScriptRegister FxScriptIREmitter::EmitVarFetch(FxAstVarRef* ref, RhsMode mode) +FoxIRRegister FoxIREmitter::EmitVarFetch(FoxAstVarRef* ref, RhsMode mode) { - FxScriptBytecodeVarHandle* var_handle = FindVarHandle(ref->Name->GetHash()); + FoxBytecodeVarHandle* var_handle = FindVarHandle(ref->Name->GetHash()); bool force_absolute_load = false; @@ -3477,14 +3474,15 @@ FxScriptRegister FxScriptIREmitter::EmitVarFetch(FxAstVarRef* ref, RhsMode mode) if (!var_handle) { printf("Could not find var handle!"); - return FX_REG_NONE; + return FX_IR_GW0; } - FxScriptRegister reg = FindFreeRegister(); + FoxIRRegister reg = FindFreeReg32(); MARK_REGISTER_USED(reg); - DoLoad(var_handle->Offset, reg, force_absolute_load); + // DoLoad(var_handle->Offset, reg, force_absolute_load); + EmitVariableGetInt32(var_handle->VarIndexInScope, reg); if (mode == RhsMode::RHS_FETCH_TO_REGISTER) { return reg; @@ -3493,21 +3491,45 @@ FxScriptRegister FxScriptIREmitter::EmitVarFetch(FxAstVarRef* ref, RhsMode mode) // If we are just copying the variable to this new variable, we can free the register after // we push to the stack. if (mode == RhsMode::RHS_DEFINE_IN_MEMORY) { - if (var_handle->Type == FxScriptValue::STRING) { + if (var_handle->Type == FoxValue::STRING) { EmitType(var_handle->Type); } - EmitPush32r(reg); + // Save the value register to the new variable + + EmitVariableSetReg32(var_handle->VarIndexInScope, reg); + // EmitPush32r(reg); MARK_REGISTER_FREE(reg); - return FX_REG_NONE; + return FX_IR_GW0; } - // This is a reference to a variable, return the register we loaded it into return reg; } -void FxScriptIREmitter::DoLoad(uint32 stack_offset, FxScriptRegister output_reg, bool force_absolute) + +uint16 FoxIREmitter::GetSizeOfType(FoxTokenizer::Token* token) +{ + const FoxHash type_hash = token->GetHash(); + + constexpr FoxHash type_int_hash = FoxHashStr("int"); + constexpr FoxHash type_float_hash = FoxHashStr("float"); + + if (type_hash == type_int_hash) { + return sizeof(int32); + } + else if (type_hash == type_float_hash) { + return sizeof(float32); + } + else { + printf("!!! UNKNOWN TYPE\n"); + } + + return 0; +} + + +void FoxIREmitter::DoLoad(uint32 stack_offset, FoxIRRegister output_reg, bool force_absolute) { if (stack_offset < 0xFFFE && !force_absolute) { // Relative load @@ -3523,7 +3545,7 @@ void FxScriptIREmitter::DoLoad(uint32 stack_offset, FxScriptRegister output_reg, } } -void FxScriptIREmitter::DoSaveInt32(uint32 stack_offset, uint32 value, bool force_absolute) +void FoxIREmitter::DoSaveInt32(uint32 stack_offset, uint32 value, bool force_absolute) { if (stack_offset < 0xFFFE && !force_absolute) { // Relative save @@ -3539,7 +3561,7 @@ void FxScriptIREmitter::DoSaveInt32(uint32 stack_offset, uint32 value, bool forc } } -void FxScriptIREmitter::DoSaveReg32(uint32 stack_offset, FxScriptRegister reg, bool force_absolute) +void FoxIREmitter::DoSaveReg32(uint32 stack_offset, FoxIRRegister reg, bool force_absolute) { if (stack_offset < 0xFFFE && !force_absolute) { // Relative save @@ -3555,9 +3577,9 @@ void FxScriptIREmitter::DoSaveReg32(uint32 stack_offset, FxScriptRegister reg, b } } -void FxScriptIREmitter::EmitAssign(FxAstAssign* assign) +void FoxIREmitter::EmitAssign(FoxAstAssign* assign) { - FxScriptBytecodeVarHandle* var_handle = FindVarHandle(assign->Var->Name->GetHash()); + FoxBytecodeVarHandle* var_handle = FindVarHandle(assign->Var->Name->GetHash()); if (var_handle == nullptr) { printf("!!! Var '%.*s' does not exist!\n", assign->Var->Name->Length, assign->Var->Name->Start); return; @@ -3579,20 +3601,20 @@ void FxScriptIREmitter::EmitAssign(FxAstAssign* assign) EmitRhs(assign->Rhs, RhsMode::RHS_ASSIGN_TO_HANDLE, var_handle); } -FxScriptRegister FxScriptIREmitter::EmitLiteralInt(FxAstLiteral* literal, RhsMode mode, FxScriptBytecodeVarHandle* handle) +FoxIRRegister FoxIREmitter::EmitLiteralInt(FoxAstLiteral* literal, RhsMode mode, FoxBytecodeVarHandle* handle) { // If this is on variable definition, push the value to the stack. if (mode == RhsMode::RHS_DEFINE_IN_MEMORY) { EmitPush32(literal->Value.ValueInt); - return FX_REG_NONE; + return FX_IR_GW3; } // If this is as a literal, push the value to the stack and pop onto the target register. else if (mode == RhsMode::RHS_FETCH_TO_REGISTER) { // EmitPush32(literal->Value.ValueInt); - FxScriptRegister output_reg = FindFreeRegister(); + FoxIRRegister output_reg = FindFreeReg32(); // EmitPop32(output_reg); EmitMoveInt32(output_reg, literal->Value.ValueInt); @@ -3605,16 +3627,17 @@ FxScriptRegister FxScriptIREmitter::EmitLiteralInt(FxAstLiteral* literal, RhsMod else if (mode == RhsMode::RHS_ASSIGN_TO_HANDLE) { const bool force_absolute_save = (handle->ScopeIndex < mScopeIndex); - DoSaveInt32(handle->Offset, literal->Value.ValueInt, force_absolute_save); + // DoSaveInt32(handle->Offset, literal->Value.ValueInt, force_absolute_save); + EmitVariableSetInt32(handle->VarIndexInScope, literal->Value.ValueInt); - return FX_REG_NONE; + return FX_IR_GW3; } - return FX_REG_NONE; + return FX_IR_GW3; } -FxScriptRegister FxScriptIREmitter::EmitLiteralString(FxAstLiteral* literal, RhsMode mode, FxScriptBytecodeVarHandle* handle) +FoxIRRegister FoxIREmitter::EmitLiteralString(FoxAstLiteral* literal, RhsMode mode, FoxBytecodeVarHandle* handle) { const uint32 string_length = strlen(literal->Value.ValueString); @@ -3624,22 +3647,22 @@ FxScriptRegister FxScriptIREmitter::EmitLiteralString(FxAstLiteral* literal, Rhs // local string some_value = "Some String"; if (mode == RhsMode::RHS_DEFINE_IN_MEMORY) { // Push the location and mark it as a pointer to a string - EmitType(FxScriptValue::STRING); + EmitType(FoxValue::STRING); EmitPush32(string_position); - return FX_REG_NONE; + return FX_IR_GW3; } // some_function("Some String") else if (mode == RhsMode::RHS_FETCH_TO_REGISTER) { // Push the location for the string and pop it back to a register. - EmitType(FxScriptValue::STRING); + EmitType(FoxValue::STRING); // Push the string position // EmitPush32(string_position); // Find a register to output to and write the index - FxScriptRegister output_reg = FindFreeRegister(); + FoxIRRegister output_reg = FindFreeReg32(); // EmitPop32(output_reg); EmitMoveInt32(output_reg, string_position); @@ -3655,49 +3678,56 @@ FxScriptRegister FxScriptIREmitter::EmitLiteralString(FxAstLiteral* literal, Rhs const bool force_absolute_save = (handle->ScopeIndex < mScopeIndex); DoSaveInt32(handle->Offset, string_position, force_absolute_save); - handle->Type = FxScriptValue::STRING; + handle->Type = FoxValue::STRING; - return FX_REG_NONE; + return FX_IR_GW3; } - return FX_REG_NONE; + return FX_IR_GW3; +} + +void FoxIREmitter::EmitMarker(IrSpecMarker spec) +{ + WriteOp(IrBase_Marker, spec); } -FxScriptRegister FxScriptIREmitter::EmitRhs(FxAstNode* rhs, FxScriptIREmitter::RhsMode mode, FxScriptBytecodeVarHandle* handle) +FoxIRRegister FoxIREmitter::EmitRhs(FoxAstNode* rhs, FoxIREmitter::RhsMode mode, FoxBytecodeVarHandle* handle) { if (rhs->NodeType == FX_AST_LITERAL) { - FxAstLiteral* literal = reinterpret_cast(rhs); + FoxAstLiteral* literal = reinterpret_cast(rhs); - if (literal->Value.Type == FxScriptValue::INT) { + if (literal->Value.Type == FoxValue::INT) { return EmitLiteralInt(literal, mode, handle); } - else if (literal->Value.Type == FxScriptValue::STRING) { + else if (literal->Value.Type == FoxValue::STRING) { return EmitLiteralString(literal, mode, handle); } - else if (literal->Value.Type == FxScriptValue::REF) { + else if (literal->Value.Type == FoxValue::REF) { // Reference another value, load from memory into register - FxScriptRegister output_register = EmitVarFetch(literal->Value.ValueRef, mode); + FoxIRRegister output_register = EmitVarFetch(literal->Value.ValueRef, mode); if (mode == IRRhsMode::RHS_ASSIGN_TO_HANDLE) { - DoSaveReg32(handle->Offset, output_register); + // DoSaveReg32(handle->Offset, output_register); + // + EmitVariableSetReg32(handle->VarIndexInScope, output_register); } return output_register; } - return FX_REG_NONE; + return FX_IR_GW3; } else if (rhs->NodeType == FX_AST_ACTIONCALL || rhs->NodeType == FX_AST_BINOP) { - FxScriptRegister result_register = FX_REG_XR; + FoxIRRegister result_register = FX_IR_GW3; if (rhs->NodeType == FX_AST_BINOP) { - result_register = EmitBinop(reinterpret_cast(rhs), handle); + result_register = EmitBinop(reinterpret_cast(rhs), handle); } else if (rhs->NodeType == FX_AST_ACTIONCALL) { - DoActionCall(reinterpret_cast(rhs)); - // Action results are stored in XR - result_register = FX_REG_XR; + DoFunctionCall(reinterpret_cast(rhs)); + // Function results are stored in XR + result_register = FX_IR_GW3; } @@ -3705,19 +3735,23 @@ FxScriptRegister FxScriptIREmitter::EmitRhs(FxAstNode* rhs, FxScriptIREmitter::R uint32 offset = mStackOffset; EmitPush32r(result_register); + MARK_REGISTER_FREE(result_register); + if (handle) { handle->Offset = offset; } - return FX_REG_NONE; + return FX_IR_GW3; } else if (mode == RhsMode::RHS_FETCH_TO_REGISTER) { // Push the result to a register EmitPush32r(result_register); + MARK_REGISTER_FREE(result_register); + // Find a register to output to, and pop the value to there. - FxScriptRegister output_reg = FindFreeRegister(); + FoxIRRegister output_reg = FindFreeReg32(); EmitPop32(output_reg); // Mark the output register as used to store it @@ -3725,63 +3759,76 @@ FxScriptRegister FxScriptIREmitter::EmitRhs(FxAstNode* rhs, FxScriptIREmitter::R return output_reg; } - else if (mode == RhsMode::RHS_ASSIGN_TO_HANDLE) { + else if (mode == IRRhsMode::RHS_ASSIGN_TO_HANDLE) { const bool force_absolute_save = (handle->ScopeIndex < mScopeIndex); // Save the value back to the variable - DoSaveReg32(handle->Offset, result_register, force_absolute_save); + // DoSaveReg32(handle->Offset, result_register, force_absolute_save); - return FX_REG_NONE; + EmitVariableSetReg32(handle->VarIndexInScope, result_register); + MARK_REGISTER_FREE(result_register); + + return FX_IR_GW3; } } - return FX_REG_NONE; + return FX_IR_GW3; } -FxScriptBytecodeVarHandle* FxScriptIREmitter::DoVarDeclare(FxAstVarDecl* decl, VarDeclareMode mode) +FoxBytecodeVarHandle* FoxIREmitter::DoVarDeclare(FoxAstVarDecl* decl, VarDeclareMode mode) { RETURN_VALUE_IF_NO_NODE(decl, nullptr); - const uint16 size_of_type = static_cast(sizeof(int32)); + // const uint16 size_of_type = static_cast(sizeof(int32)); - const FxHash type_int = FxHashStr("int"); - const FxHash type_string = FxHashStr("string"); + const FoxHash type_int = FoxHashStr("int"); + const FoxHash type_string = FoxHashStr("string"); - FxHash decl_hash = decl->Name->GetHash(); + FoxHash decl_hash = decl->Name->GetHash(); + FoxHash type_hash = decl->Type->GetHash(); - FxScriptValue::ValueType value_type = FxScriptValue::INT; + FoxValue::ValueType value_type = FoxValue::INT; - switch (decl_hash) { + switch (type_hash) { case type_int: - value_type = FxScriptValue::INT; + value_type = FoxValue::INT; break; case type_string: - value_type = FxScriptValue::STRING; + value_type = FoxValue::STRING; break; }; - FxScriptBytecodeVarHandle handle { - .HashedName = decl->Name->GetHash(), - .Type = value_type, // Just int for now - .Offset = (mStackOffset), - .SizeOnStack = size_of_type, - .ScopeIndex = mScopeIndex, - }; + const uint16 size_of_type = GetSizeOfType(decl->Type); - VarHandles.Insert(handle); + // FoxBytecodeVarHandle handle { + // .HashedName = decl_hash, + // .Type = value_type, // Just int for now + // .Offset = (mStackOffset), + // .SizeOnStack = size_of_type, + // .ScopeIndex = mScopeIndex, + // }; - FxScriptBytecodeVarHandle* inserted_handle = &VarHandles[VarHandles.Size() - 1]; + // VarHandles.Insert(handle); + + // FoxBytecodeVarHandle* inserted_handle = &VarHandles[VarHandles.Size() - 1]; + + FoxBytecodeVarHandle* var_handle = FindVarHandle(decl_hash); + + if (var_handle == nullptr) { + printf("!!! Could not find var handle!\n"); + return nullptr; + } if (mode == DECLARE_NO_EMIT) { // Do not emit any values - return inserted_handle; + return var_handle; } if (decl->Assignment) { - FxAstNode* rhs = decl->Assignment->Rhs; + FoxAstNode* rhs = decl->Assignment->Rhs; - EmitRhs(rhs, RhsMode::RHS_DEFINE_IN_MEMORY, inserted_handle); + EmitRhs(rhs, RhsMode::RHS_ASSIGN_TO_HANDLE, var_handle); // EmitPush32(0); @@ -3794,22 +3841,22 @@ FxScriptBytecodeVarHandle* FxScriptIREmitter::DoVarDeclare(FxAstVarDecl* decl, V EmitPush32(0); } - return inserted_handle; + return var_handle; } -void FxScriptIREmitter::DoActionCall(FxAstActionCall* call) +void FoxIREmitter::DoFunctionCall(FoxAstFunctionCall* call) { RETURN_IF_NO_NODE(call); - FxScriptBytecodeActionHandle* handle = FindActionHandle(call->HashedName); + FoxBytecodeFunctionHandle* handle = FindFunctionHandle(call->HashedName); std::vector call_locations; call_locations.reserve(8); // Push all params to stack - for (FxAstNode* param : call->Params) { - // FxScriptRegister reg = + for (FoxAstNode* param : call->Params) { + // FoxRegister reg = if (param->NodeType == FX_AST_ACTIONCALL) { EmitRhs(param, RhsMode::RHS_DEFINE_IN_MEMORY, nullptr); call_locations.push_back(mStackOffset - 4); @@ -3817,16 +3864,16 @@ void FxScriptIREmitter::DoActionCall(FxAstActionCall* call) // MARK_REGISTER_FREE(reg); } - EmitPush32r(FX_REG_RA); + // EmitPush32r(FX_REG_RA); EmitParamsStart(); int call_location_index = 0; // Push all params to stack - for (FxAstNode* param : call->Params) { + for (FoxAstNode* param : call->Params) { if (param->NodeType == FX_AST_ACTIONCALL) { - FxScriptRegister temp_register = FindFreeRegister(); + FoxIRRegister temp_register = FindFreeReg32(); DoLoad(call_locations[call_location_index], temp_register); call_location_index++; @@ -3851,16 +3898,16 @@ void FxScriptIREmitter::DoActionCall(FxAstActionCall* call) EmitJumpCallExternal(call->HashedName); - EmitPop32(FX_REG_RA); + // EmitPop32(FX_REG_RA); return; } EmitJumpCallAbsolute(handle->BytecodeIndex); - EmitPop32(FX_REG_RA); + // EmitPop32(FX_REG_RA); } -FxScriptBytecodeVarHandle* FxScriptIREmitter::DefineAndFetchParam(FxAstNode* param_decl_node) +FoxBytecodeVarHandle* FoxIREmitter::DefineAndFetchParam(FoxAstNode* param_decl_node) { if (param_decl_node->NodeType != FX_AST_VARDECL) { printf("!!! param node type is not vardecl!\n"); @@ -3868,7 +3915,7 @@ FxScriptBytecodeVarHandle* FxScriptIREmitter::DefineAndFetchParam(FxAstNode* par } // Emit variable without emitting pushes or pops - FxScriptBytecodeVarHandle* handle = DoVarDeclare(reinterpret_cast(param_decl_node), DECLARE_NO_EMIT); + FoxBytecodeVarHandle* handle = DoVarDeclare(reinterpret_cast(param_decl_node), DECLARE_NO_EMIT); if (!handle) { printf("!!! could not define and fetch param!\n"); @@ -3882,62 +3929,66 @@ FxScriptBytecodeVarHandle* FxScriptIREmitter::DefineAndFetchParam(FxAstNode* par return handle; } -FxScriptBytecodeVarHandle* FxScriptIREmitter::DefineReturnVar(FxAstVarDecl* decl) +FoxBytecodeVarHandle* FoxIREmitter::DefineReturnVar(FoxAstVarDecl* decl) { RETURN_VALUE_IF_NO_NODE(decl, nullptr); return DoVarDeclare(decl); } -void FxScriptIREmitter::EmitAction(FxAstActionDecl* action) +void FoxIREmitter::EmitFunction(FoxAstFunctionDecl* function) { - RETURN_IF_NO_NODE(action); + RETURN_IF_NO_NODE(function); ++mScopeIndex; - // Store the bytecode offset before the action is emitted + // Store the bytecode offset before the function is emitted - const size_t start_of_action = mBytecode.Size(); - printf("Start of action %zu\n", start_of_action); + const size_t start_of_function = mBytecode.Size(); + printf("Start of function %zu\n", start_of_function); // Emit the jump instruction, we will update the jump position after emitting all of the code inside the block EmitJumpRelative(0); // const uint32 initial_stack_offset = mStackOffset; - const size_t header_jump_start_index = start_of_action + sizeof(uint16); + const size_t header_jump_start_index = start_of_function + sizeof(uint16); size_t start_var_handle_count = VarHandles.Size(); // Offset for the pushed return address mStackOffset += 4; - // Emit the body of the action + // Emit the body of the function { - for (FxAstNode* param_decl_node : action->Params->Statements) { + for (FoxAstNode* param_decl_node : function->Params->Statements) { DefineAndFetchParam(param_decl_node); } - FxScriptBytecodeVarHandle* return_var = DefineReturnVar(action->ReturnVar); + FoxBytecodeVarHandle* return_var = DefineReturnVar(function->ReturnVar); - EmitBlock(action->Block); + EmitBlock(function->Block); - // Check to see if there has been a return statement in the action + // Check to see if there has been a return statement in the function bool block_has_return = false; - for (FxAstNode* statement : action->Block->Statements) { + for (FoxAstNode* statement : function->Block->Statements) { if (statement->NodeType == FX_AST_RETURN) { block_has_return = true; break; } } - // There is no return statement in the action's block, add a return statement + // There is no return statement in the function's block, add a return statement if (!block_has_return) { EmitJumpReturnToCaller(); + FoxIRRegister result_register = FindFreeReg32(); + + MARK_REGISTER_USED(result_register); + if (return_var != nullptr) { - DoLoad(return_var->Offset, FX_REG_XR); + DoLoad(return_var->Offset, result_register); } } } @@ -3945,40 +3996,70 @@ void FxScriptIREmitter::EmitAction(FxAstActionDecl* action) // Return offset back to pre-call mStackOffset -= 4; - const size_t end_of_action = mBytecode.Size(); - const uint16 distance_to_action = static_cast(end_of_action - (start_of_action)-4); + const size_t end_of_function = mBytecode.Size(); + const uint16 distance_to_function = static_cast(end_of_function - (start_of_function)-4); - // Update the jump to the end of the action - mBytecode[header_jump_start_index] = static_cast(distance_to_action >> 8); - mBytecode[header_jump_start_index + 1] = static_cast((distance_to_action & 0xFF)); + // Update the jump to the end of the function + mBytecode[header_jump_start_index] = static_cast(distance_to_function >> 8); + mBytecode[header_jump_start_index + 1] = static_cast((distance_to_function & 0xFF)); - FxScriptBytecodeActionHandle action_handle {.HashedName = action->Name->GetHash(), .BytecodeIndex = static_cast(start_of_action + 4)}; + FoxBytecodeFunctionHandle function_handle {.HashedName = function->Name->GetHash(), .BytecodeIndex = static_cast(start_of_function + 4)}; const size_t number_of_scope_var_handles = VarHandles.Size() - start_var_handle_count; printf("Number of var handles to remove: %zu\n", number_of_scope_var_handles); - ActionHandles.push_back(action_handle); + FunctionHandles.push_back(function_handle); --mScopeIndex; // Delete the variables on the stack for (int i = 0; i < number_of_scope_var_handles; i++) { - FxScriptBytecodeVarHandle* var = VarHandles.RemoveLast(); + FoxBytecodeVarHandle* var = VarHandles.RemoveLast(); assert(var->SizeOnStack == 4); mStackOffset -= var->SizeOnStack; } } -void FxScriptIREmitter::EmitBlock(FxAstBlock* block) +void FoxIREmitter::EmitBlock(FoxAstBlock* block) { RETURN_IF_NO_NODE(block); - for (FxAstNode* node : block->Statements) { + EmitMarker(IrSpecMarker_FrameBegin); + + + // For each var declared in the block, write a stack allocation in the frame header + for (FoxAstNode* node : block->Statements) { + if (node->NodeType == FX_AST_VARDECL) { + FoxAstVarDecl* var_decl = reinterpret_cast(node); + + uint32 stack_index = mStackOffset; + + EmitStackAlloc(GetSizeOfType(var_decl->Type)); + + FoxBytecodeVarHandle var_handle { + .HashedName = var_decl->Name->GetHash(), + .Offset = stack_index, + .ScopeIndex = mScopeIndex, + + .VarIndexInScope = mVarsInScope, + .Type = FoxValue::INT, + }; + + VarHandles.Insert(var_handle); + + ++mVarsInScope; + } + } + + for (FoxAstNode* node : block->Statements) { Emit(node); } + + mVarsInScope = 0; + EmitMarker(IrSpecMarker_FrameEnd); } -void FxScriptIREmitter::PrintBytecode() +void FoxIREmitter::PrintBytecode() { const size_t size = mBytecode.Size(); for (int i = 0; i < 25; i++) { @@ -4007,7 +4088,7 @@ void FxScriptIREmitter::PrintBytecode() // Bytecode Printer ///////////////////////////////////// -uint16 FxScriptIRPrinter::Read16() +uint16 FoxIRPrinter::Read16() { uint8 lo = mBytecode[mBytecodeIndex++]; uint8 hi = mBytecode[mBytecodeIndex++]; @@ -4015,7 +4096,7 @@ uint16 FxScriptIRPrinter::Read16() return ((static_cast(lo) << 8) | hi); } -uint32 FxScriptIRPrinter::Read32() +uint32 FoxIRPrinter::Read32() { uint16 lo = Read16(); uint16 hi = Read16(); @@ -4025,22 +4106,22 @@ uint32 FxScriptIRPrinter::Read32() #define BC_PRINT_OP(fmt_, ...) snprintf(s, 128, fmt_, ##__VA_ARGS__) -void FxScriptIRPrinter::DoLoad(char* s, uint8 op_base, uint8 op_spec_raw) +void FoxIRPrinter::DoLoad(char* s, uint8 op_base, uint8 op_spec_raw) { uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); uint8 op_reg = (op_spec_raw & 0x0F); if (op_spec == IrSpecLoad_Int32) { int16 offset = Read16(); - BC_PRINT_OP("load32 %d, %s", offset, FxScriptIREmitter::GetRegisterName(static_cast(op_reg))); + BC_PRINT_OP("load32 %d, %s", offset, FoxIREmitter::GetRegisterName(static_cast(op_reg))); } else if (op_spec == IrSpecLoad_AbsoluteInt32) { uint32 offset = Read32(); - BC_PRINT_OP("load32a %u, %s", offset, FxScriptIREmitter::GetRegisterName(static_cast(op_reg))); + BC_PRINT_OP("load32a %u, %s", offset, FoxIREmitter::GetRegisterName(static_cast(op_reg))); } } -void FxScriptIRPrinter::DoPush(char* s, uint8 op_base, uint8 op_spec) +void FoxIRPrinter::DoPush(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == IrSpecPush_Int32) { uint32 value = Read32(); @@ -4048,32 +4129,36 @@ void FxScriptIRPrinter::DoPush(char* s, uint8 op_base, uint8 op_spec) } else if (op_spec == IrSpecPush_Reg32) { uint16 reg = Read16(); - BC_PRINT_OP("push32r %s", FxScriptIREmitter::GetRegisterName(static_cast(reg))); + BC_PRINT_OP("push32r %s", FoxIREmitter::GetRegisterName(static_cast(reg))); + } + else if (op_spec == IrSpecPush_StackAlloc) { + uint16 size = Read16(); + BC_PRINT_OP("salloc %d", size); } } -void FxScriptIRPrinter::DoPop(char* s, uint8 op_base, uint8 op_spec_raw) +void FoxIRPrinter::DoPop(char* s, uint8 op_base, uint8 op_spec_raw) { uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); uint8 op_reg = (op_spec_raw & 0x0F); - if (op_spec == IrSpecPush_Int32) { - BC_PRINT_OP("pop32 %s", FxScriptIREmitter::GetRegisterName(static_cast(op_reg))); + if (op_spec == IrSpecPop_Int32) { + BC_PRINT_OP("pop32 %s", FoxIREmitter::GetRegisterName(static_cast(op_reg))); } } -void FxScriptIRPrinter::DoArith(char* s, uint8 op_base, uint8 op_spec) +void FoxIRPrinter::DoArith(char* s, uint8 op_base, uint8 op_spec) { uint8 a_reg = mBytecode[mBytecodeIndex++]; uint8 b_reg = mBytecode[mBytecodeIndex++]; if (op_spec == IrSpecArith_Add) { - BC_PRINT_OP("add32 %s, %s", FxScriptIREmitter::GetRegisterName(static_cast(a_reg)), - FxScriptIREmitter::GetRegisterName(static_cast(b_reg))); + BC_PRINT_OP("add32 %s, %s", FoxIREmitter::GetRegisterName(static_cast(a_reg)), + FoxIREmitter::GetRegisterName(static_cast(b_reg))); } } -void FxScriptIRPrinter::DoSave(char* s, uint8 op_base, uint8 op_spec) +void FoxIRPrinter::DoSave(char* s, uint8 op_base, uint8 op_spec) { // Save a imm32 into an offset in the stack if (op_spec == IrSpecSave_Int32) { @@ -4088,7 +4173,7 @@ void FxScriptIRPrinter::DoSave(char* s, uint8 op_base, uint8 op_spec) const int16 offset = Read16(); uint16 reg = Read16(); - BC_PRINT_OP("save32r %d, %s", offset, FxScriptIREmitter::GetRegisterName(static_cast(reg))); + BC_PRINT_OP("save32r %d, %s", offset, FoxIREmitter::GetRegisterName(static_cast(reg))); } else if (op_spec == IrSpecSave_AbsoluteInt32) { const uint32 offset = Read32(); @@ -4100,11 +4185,11 @@ void FxScriptIRPrinter::DoSave(char* s, uint8 op_base, uint8 op_spec) const uint32 offset = Read32(); uint16 reg = Read16(); - BC_PRINT_OP("save32ar %u, %s", offset, FxScriptIREmitter::GetRegisterName(static_cast(reg))); + BC_PRINT_OP("save32ar %u, %s", offset, FoxIREmitter::GetRegisterName(static_cast(reg))); } } -void FxScriptIRPrinter::DoJump(char* s, uint8 op_base, uint8 op_spec) +void FoxIRPrinter::DoJump(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == IrSpecJump_Relative) { uint16 offset = Read16(); @@ -4117,7 +4202,7 @@ void FxScriptIRPrinter::DoJump(char* s, uint8 op_base, uint8 op_spec) } else if (op_spec == IrSpecJump_AbsoluteReg32) { uint16 reg = Read16(); - BC_PRINT_OP("jmpar %s", FxScriptIREmitter::GetRegisterName(static_cast(reg))); + BC_PRINT_OP("jmpar %s", FoxIREmitter::GetRegisterName(static_cast(reg))); } else if (op_spec == IrSpecJump_CallAbsolute) { uint32 position = Read32(); @@ -4132,7 +4217,8 @@ void FxScriptIRPrinter::DoJump(char* s, uint8 op_base, uint8 op_spec) } } -void FxScriptIRPrinter::DoData(char* s, uint8 op_base, uint8 op_spec) + +void FoxIRPrinter::DoData(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == IrSpecData_String) { uint16 length = Read16(); @@ -4150,12 +4236,9 @@ void FxScriptIRPrinter::DoData(char* s, uint8 op_base, uint8 op_spec) FX_SCRIPT_FREE(char, data_str); } - else if (op_spec == IrSpecData_ParamsStart) { - BC_PRINT_OP("paramsstart"); - } } -void FxScriptIRPrinter::DoType(char* s, uint8 op_base, uint8 op_spec) +void FoxIRPrinter::DoType(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == IrSpecType_Int) { BC_PRINT_OP("typeint"); @@ -4165,26 +4248,59 @@ void FxScriptIRPrinter::DoType(char* s, uint8 op_base, uint8 op_spec) } } -void FxScriptIRPrinter::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) +void FoxIRPrinter::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) { uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); uint8 op_reg = (op_spec_raw & 0x0F); if (op_spec == IrSpecMove_Int32) { uint32 value = Read32(); - BC_PRINT_OP("move32 %s, %u\t", FxScriptIREmitter::GetRegisterName(static_cast(op_reg)), value); + BC_PRINT_OP("move32 %s, %u\t", FoxIREmitter::GetRegisterName(static_cast(op_reg)), value); + } +} + +void FoxIRPrinter::DoMarker(char* s, uint8 op_base, uint8 op_spec) +{ + if (op_spec == IrSpecMarker_FrameBegin) { + BC_PRINT_OP("frame begin"); + } + else if (op_spec == IrSpecMarker_FrameEnd) { + BC_PRINT_OP("frame end"); + } + else if (op_spec == IrSpecMarker_ParamsBegin) { + BC_PRINT_OP("params begin"); + } +} + + +void FoxIRPrinter::DoVariable(char* s, uint8 op_base, uint8 op_spec) +{ + if (op_spec == IrSpecVariable_Get_Int32) { + uint16 var_index = Read16(); + FoxIRRegister dest_reg = static_cast(Read16()); + BC_PRINT_OP("vget $%d, %s", var_index, FoxIREmitter::GetRegisterName(dest_reg)); + } + else if (op_spec == IrSpecVariable_Set_Int32) { + uint16 var_index = Read16(); + uint32 value = Read32(); + BC_PRINT_OP("vset $%d, %d", var_index, value); + } + else if (op_spec == IrSpecVariable_Set_Reg32) { + uint16 var_index = Read16(); + FoxIRRegister reg = static_cast(Read16()); + BC_PRINT_OP("vset $%d, %s", var_index, FoxIREmitter::GetRegisterName(reg)); } } -void FxScriptIRPrinter::Print() +void FoxIRPrinter::Print() { while (mBytecodeIndex < mBytecode.Size()) { PrintOp(); } } -void FxScriptIRPrinter::PrintOp() +void FoxIRPrinter::PrintOp() { uint32 bc_index = mBytecodeIndex; @@ -4223,6 +4339,12 @@ void FxScriptIRPrinter::PrintOp() case IrBase_Move: DoMove(s, op_base, op_spec); break; + case IrBase_Marker: + DoMarker(s, op_base, op_spec); + break; + case IrBase_Variable: + DoVariable(s, op_base, op_spec); + break; } printf("%-25s", s); diff --git a/FoxScript.hpp b/FoxScript.hpp new file mode 100644 index 0000000..d8c9bda --- /dev/null +++ b/FoxScript.hpp @@ -0,0 +1,1212 @@ +#pragma once + +#include "FoxMPPagedArray.hpp" +#include "FoxTokenizer.hpp" + +#include + +#define FX_SCRIPT_VERSION_MAJOR 0 +#define FX_SCRIPT_VERSION_MINOR 3 +#define FX_SCRIPT_VERSION_PATCH 1 + +#define FX_SCRIPT_VAR_RETURN_VAL "__ReturnVal__" + + +struct FoxAstVarRef; +struct FoxScope; +struct FoxFunction; + +struct FoxValue +{ + static FoxValue None; + + enum ValueType : uint16 + { + NONETYPE = 0x00, + INT = 0x01, + FLOAT = 0x02, + STRING = 0x04, + VEC3 = 0x08, + REF = 0x10 + }; + + ValueType Type = NONETYPE; + + union + { + int ValueInt = 0; + float ValueFloat; + float ValueVec3[3]; + char* ValueString; + + FoxAstVarRef* ValueRef; + }; + + FoxValue() + { + } + + explicit FoxValue(ValueType type, int value) : Type(type), ValueInt(value) + { + } + + explicit FoxValue(ValueType type, float value) : Type(type), ValueFloat(value) + { + } + + FoxValue(const FoxValue& other) + { + Type = other.Type; + if (other.Type == INT) { + ValueInt = other.ValueInt; + } + else if (other.Type == FLOAT) { + ValueFloat = other.ValueFloat; + } + else if (other.Type == STRING) { + ValueString = other.ValueString; + } + else if (other.Type == REF) { + ValueRef = other.ValueRef; + } + } + + void Print() const + { + printf("[Value: "); + if (Type == NONETYPE) { + printf("Null]\n"); + } + else if (Type == INT) { + printf("Int, %d]\n", ValueInt); + } + else if (Type == FLOAT) { + printf("Float, %f]\n", ValueFloat); + } + else if (Type == STRING) { + printf("String, %s]\n", ValueString); + } + else if (Type == REF) { + printf("Ref, %p]\n", ValueRef); + } + } + + inline bool IsNumber() + { + return (Type == INT || Type == FLOAT); + } + + inline bool IsRef() + { + return (Type == REF); + } +}; + +enum FoxAstType +{ + FX_AST_LITERAL, + // FX_AST_NAME, + + FX_AST_BINOP, + FX_AST_UNARYOP, + FX_AST_BLOCK, + + // Variables + FX_AST_VARREF, + FX_AST_VARDECL, + FX_AST_ASSIGN, + + // Functions + FX_AST_ACTIONDECL, + FX_AST_ACTIONCALL, + FX_AST_RETURN, + + FX_AST_DOCCOMMENT, + + FX_AST_COMMANDMODE, +}; + +struct FoxAstNode +{ + FoxAstType NodeType; +}; + + +struct FoxAstLiteral : public FoxAstNode +{ + FoxAstLiteral() + { + this->NodeType = FX_AST_LITERAL; + } + + // FoxTokenizer::Token* Token = nullptr; + FoxValue Value; +}; + +struct FoxAstBinop : public FoxAstNode +{ + FoxAstBinop() + { + this->NodeType = FX_AST_BINOP; + } + + FoxTokenizer::Token* OpToken = nullptr; + FoxAstNode* Left = nullptr; + FoxAstNode* Right = nullptr; +}; + +struct FoxAstBlock : public FoxAstNode +{ + FoxAstBlock() + { + this->NodeType = FX_AST_BLOCK; + } + + std::vector Statements; +}; + +struct FoxAstVarRef : public FoxAstNode +{ + FoxAstVarRef() + { + this->NodeType = FX_AST_VARREF; + } + + FoxTokenizer::Token* Name = nullptr; + FoxScope* Scope = nullptr; +}; + +struct FoxAstAssign : public FoxAstNode +{ + FoxAstAssign() + { + this->NodeType = FX_AST_ASSIGN; + } + + FoxAstVarRef* Var = nullptr; + // FoxValue Value; + FoxAstNode* Rhs = nullptr; +}; + +struct FoxAstVarDecl : public FoxAstNode +{ + FoxAstVarDecl() + { + this->NodeType = FX_AST_VARDECL; + } + + FoxTokenizer::Token* Name = nullptr; + FoxTokenizer::Token* Type = nullptr; + FoxAstAssign* Assignment = nullptr; + + /// Ignore the scope that the variable is declared in, force it to be global. + bool DefineAsGlobal = false; +}; + +struct FoxAstDocComment : public FoxAstNode +{ + FoxAstDocComment() + { + this->NodeType = FX_AST_DOCCOMMENT; + } + + FoxTokenizer::Token* Comment; +}; + +struct FoxAstFunctionDecl : public FoxAstNode +{ + FoxAstFunctionDecl() + { + this->NodeType = FX_AST_ACTIONDECL; + } + + FoxTokenizer::Token* Name = nullptr; + FoxAstVarDecl* ReturnVar = nullptr; + FoxAstBlock* Params = nullptr; + FoxAstBlock* Block = nullptr; + + std::vector DocComments; +}; + +struct FoxAstCommandMode : public FoxAstNode +{ + FoxAstCommandMode() + { + this->NodeType = FX_AST_COMMANDMODE; + } + + FoxAstNode* Node = nullptr; +}; + +struct FoxAstFunctionCall : public FoxAstNode +{ + FoxAstFunctionCall() + { + this->NodeType = FX_AST_ACTIONCALL; + } + + FoxFunction* Function = nullptr; + FoxHash HashedName = 0; + std::vector Params {}; // FoxAstLiteral or FoxAstVarRef +}; + +struct FoxAstReturn : public FoxAstNode +{ + FoxAstReturn() + { + this->NodeType = FX_AST_RETURN; + } +}; + +/** + * @brief Data is accessible from a label, such as a variable or an function. + */ +struct FoxLabelledData +{ + FoxHash HashedName = 0; + FoxTokenizer::Token* Name = nullptr; + + FoxScope* Scope = nullptr; +}; + +struct FoxFunction : public FoxLabelledData +{ + FoxFunction(FoxTokenizer::Token* name, FoxScope* scope, FoxAstBlock* block, FoxAstFunctionDecl* declaration) + { + HashedName = name->GetHash(); + Name = name; + Scope = scope; + Block = block; + Declaration = declaration; + } + + FoxAstFunctionDecl* Declaration = nullptr; + FoxAstBlock* Block = nullptr; +}; + +struct FoxVar : public FoxLabelledData +{ + FoxTokenizer::Token* Type = nullptr; + FoxValue Value; + + bool IsExternal = false; + + void Print() const + { + printf("[Var] Type: %.*s, Name: %.*s (Hash:%u)", Type->Length, Type->Start, Name->Length, Name->Start, Name->GetHash()); + Value.Print(); + } + + FoxVar() + { + } + + FoxVar(FoxTokenizer::Token* type, FoxTokenizer::Token* name, FoxScope* scope, bool is_external = false) : Type(type) + { + this->HashedName = name->GetHash(); + this->Name = name; + this->Scope = scope; + IsExternal = is_external; + } + + FoxVar(const FoxVar& other) + { + HashedName = other.HashedName; + Type = other.Type; + Name = other.Name; + Value = other.Value; + IsExternal = other.IsExternal; + } + + FoxVar& operator=(FoxVar&& other) noexcept + { + HashedName = other.HashedName; + Type = other.Type; + Name = other.Name; + Value = other.Value; + IsExternal = other.IsExternal; + + Name = nullptr; + Type = nullptr; + HashedName = 0; + + return *this; + } + + ~FoxVar() + { + if (!IsExternal) { + return; + } + + // Free tokens allocated by external variables + if (Type && Type->Start) { + FX_SCRIPT_FREE(char, Type->Start); + } + + if (this->Name && this->Name->Start) { + FX_SCRIPT_FREE(char, this->Name->Start); + } + } +}; + +class FoxVM; + + +struct FoxExternalFunc +{ + // using FuncType = void (*)(FoxInterpreter& interpreter, std::vector& params, FoxValue* return_value); + + using FuncType = void (*)(FoxVM* vm, std::vector& params, FoxValue* return_value); + + FoxHash HashedName = 0; + FuncType Function = nullptr; + + std::vector ParameterTypes; + bool IsVariadic = false; +}; + +struct FoxScope +{ + FoxMPPagedArray Vars; + FoxMPPagedArray Functions; + + FoxScope* Parent = nullptr; + + // This points to the return value for the current scope. If an function returns a value, + // this will be set to the variable that holds its value. This is interpreter only. + FoxVar* ReturnVar = nullptr; + + void PrintAllVarsInScope() + { + puts("\n=== SCOPE ==="); + for (FoxVar& var : Vars) { + var.Print(); + } + } + + FoxVar* FindVarInScope(FoxHash hashed_name) + { + return FindInScope(hashed_name, Vars); + } + + FoxFunction* FindFunctionInScope(FoxHash hashed_name) + { + return FindInScope(hashed_name, Functions); + } + + template + requires std::is_base_of_v + T* FindInScope(FoxHash hashed_name, const FoxMPPagedArray& buffer) + { + for (T& var : buffer) { + if (var.HashedName == hashed_name) { + return &var; + } + } + + return nullptr; + } +}; + +// class FoxInterpreter; + +class FoxConfigScript +{ + using Token = FoxTokenizer::Token; + using TT = FoxTokenizer::TokenType; + +public: + FoxConfigScript() = default; + + void LoadFile(const char* path); + + void PushScope(); + void PopScope(); + + FoxVar* FindVar(FoxHash hashed_name); + + FoxFunction* FindFunction(FoxHash hashed_name); + FoxExternalFunc* FindExternalFunction(FoxHash hashed_name); + + FoxAstNode* TryParseKeyword(FoxAstBlock* parent_block); + + FoxAstAssign* TryParseAssignment(FoxTokenizer::Token* var_name); + + FoxValue ParseValue(); + + FoxAstFunctionDecl* ParseFunctionDeclare(); + + FoxAstNode* ParseRhs(); + FoxAstFunctionCall* ParseFunctionCall(); + + /** + * @brief Declares a variable for internal uses as if it was declared in the script. + * @param name Name of the variable + * @param type The name of the type + * @param scope The scope the variable will be declared in + * @return + */ + FoxAstVarDecl* InternalVarDeclare(FoxTokenizer::Token* name_token, FoxTokenizer::Token* type_token, FoxScope* scope = nullptr); + FoxAstVarDecl* ParseVarDeclare(FoxScope* scope = nullptr); + + FoxAstBlock* ParseBlock(); + + FoxAstNode* ParseStatement(FoxAstBlock* parent_block); + FoxAstNode* ParseStatementAsCommand(FoxAstBlock* parent_block); + + FoxAstBlock* Parse(); + + /** + * @brief Parses and executes a script. + * @param interpreter The interpreter to execute with + */ + void Execute(FoxVM& vm); + + /** + * @brief Executes a command on a script. Defaults to parsing with command style syntax. + * @param command The command to execute on the script. + * @return If the command has been executed + */ + // bool ExecuteUserCommand(const char* command, FoxInterpreter& interpreter); + + Token& GetToken(int offset = 0); + Token& EatToken(TT token_type); + + void RegisterExternalFunc(FoxHash func_name, std::vector param_types, FoxExternalFunc::FuncType func, bool is_variadic); + + void DefineExternalVar(const char* type, const char* name, const FoxValue& value); + +private: + template + requires std::is_base_of_v + T* FindLabelledData(FoxHash hashed_name, FoxMPPagedArray& buffer) + { + FoxScope* scope = mCurrentScope; + + while (scope) { + T* var = scope->FindInScope(hashed_name, buffer); + if (var) { + return var; + } + + scope = scope->Parent; + } + + return nullptr; + } + + void DefineDefaultExternalFunctions(); + + Token* CreateTokenFromString(FoxTokenizer::TokenType type, const char* text); + void CreateInternalVariableTokens(); + +private: + FoxMPPagedArray mScopes; + FoxScope* mCurrentScope; + + std::vector mExternalFuncs; + + std::vector CurrentDocComments; + + FoxAstBlock* mRootBlock = nullptr; + + bool mHasErrors = false; + bool mInCommandMode = false; + + char* mFileData; + FoxMPPagedArray mTokens = {}; + uint32 mTokenIndex = 0; + + // Name tokens for internal variables + Token* mTokenReturnVar = nullptr; +}; + +////////////////////////////////// +// Script AST Printer +////////////////////////////////// + +class FoxAstPrinter +{ +public: + FoxAstPrinter(FoxAstBlock* root_block) + //: mRootBlock(root_block) + { + } + + void Print(FoxAstNode* node, int depth = 0) + { + if (node == nullptr) { + return; + } + + for (int i = 0; i < depth; i++) { + putchar(' '); + putchar(' '); + } + + if (node->NodeType == FX_AST_BLOCK) { + puts("[BLOCK]"); + + FoxAstBlock* block = reinterpret_cast(node); + for (FoxAstNode* child : block->Statements) { + Print(child, depth + 1); + } + return; + } + else if (node->NodeType == FX_AST_ACTIONDECL) { + FoxAstFunctionDecl* functiondecl = reinterpret_cast(node); + printf("[ACTIONDECL] "); + functiondecl->Name->Print(); + + for (FoxAstNode* param : functiondecl->Params->Statements) { + Print(param, depth + 1); + } + + Print(functiondecl->Block, depth + 1); + } + else if (node->NodeType == FX_AST_VARDECL) { + FoxAstVarDecl* vardecl = reinterpret_cast(node); + + printf("[VARDECL] "); + vardecl->Name->Print(); + + Print(vardecl->Assignment, depth + 1); + } + else if (node->NodeType == FX_AST_ASSIGN) { + FoxAstAssign* assign = reinterpret_cast(node); + + printf("[ASSIGN] "); + + assign->Var->Name->Print(); + Print(assign->Rhs, depth + 1); + } + else if (node->NodeType == FX_AST_ACTIONCALL) { + FoxAstFunctionCall* functioncall = reinterpret_cast(node); + + printf("[ACTIONCALL] "); + if (functioncall->Function == nullptr) { + printf("{defined externally}"); + } + else { + functioncall->Function->Name->Print(true); + } + + printf(" (%zu params)\n", functioncall->Params.size()); + } + else if (node->NodeType == FX_AST_LITERAL) { + FoxAstLiteral* literal = reinterpret_cast(node); + + printf("[LITERAL] "); + literal->Value.Print(); + } + else if (node->NodeType == FX_AST_BINOP) { + FoxAstBinop* binop = reinterpret_cast(node); + + printf("[BINOP] "); + binop->OpToken->Print(); + + Print(binop->Left, depth + 1); + Print(binop->Right, depth + 1); + } + else if (node->NodeType == FX_AST_COMMANDMODE) { + FoxAstCommandMode* command_mode = reinterpret_cast(node); + printf("[COMMANDMODE]\n"); + + Print(command_mode->Node, depth + 1); + } + else if (node->NodeType == FX_AST_RETURN) { + puts("[RETURN]"); + } + else { + puts("[UNKNOWN]"); + } + // else if (node->NodeType == FX_AST_) + } + +public: + // FoxAstBlock* mRootBlock = nullptr; +}; + +///////////////////////////////////////////// +// Script Bytecode Emitter +///////////////////////////////////////////// + +enum FoxBCRegister : uint8 +{ + FX_REG_NONE = 0x00, + FX_REG_X0, + FX_REG_X1, + FX_REG_X2, + FX_REG_X3, + + /** + * @brief Return address register. + */ + FX_REG_RA, + + /** + * @brief Register that contains the result of an operation. + */ + FX_REG_XR, + + /** + * @brief Register that contains the stack pointer for the VM. + */ + FX_REG_SP, + + FX_REG_SIZE, +}; + + +enum FoxRegisterFlag : uint16 +{ + FX_REGFLAG_NONE = 0x00, + FX_REGFLAG_X0 = 0x01, + FX_REGFLAG_X1 = 0x02, + FX_REGFLAG_X2 = 0x04, + FX_REGFLAG_X3 = 0x08, + FX_REGFLAG_RA = 0x10, + FX_REGFLAG_XR = 0x20, +}; + + +enum FoxIRRegister : uint8 +{ + /* General Purpose (32 bit) registers */ + FX_IR_GW0, + FX_IR_GW1, + FX_IR_GW2, + FX_IR_GW3, + + /* General Purpose (64 bit) registers */ + FX_IR_GX0, + FX_IR_GX1, + FX_IR_GX2, + FX_IR_GX3, + + /* Stack pointer */ + FX_IR_SP, +}; + +inline FoxRegisterFlag operator|(FoxRegisterFlag a, FoxRegisterFlag b) +{ + return static_cast(static_cast(a) | static_cast(b)); +} + +inline FoxRegisterFlag operator&(FoxRegisterFlag a, FoxRegisterFlag b) +{ + return static_cast(static_cast(a) & static_cast(b)); +} + +struct FoxBytecodeVarHandle +{ + FoxHash HashedName = 0; + FoxValue::ValueType Type = FoxValue::INT; + int64 Offset = 0; + + uint16 VarIndexInScope = 0; + + uint16 SizeOnStack = 4; + uint32 ScopeIndex = 0; +}; + +struct FoxBytecodeFunctionHandle +{ + FoxHash HashedName = 0; + uint32 BytecodeIndex = 0; +}; + +class FoxBCEmitter +{ +public: + FoxBCEmitter() = default; + + void BeginEmitting(FoxAstNode* node); + void Emit(FoxAstNode* node); + + enum RhsMode + { + RHS_FETCH_TO_REGISTER, + + /** + * @brief Pushes the value to the stack, assuming that the value does not exist yet. + */ + RHS_DEFINE_IN_MEMORY, + + RHS_ASSIGN_TO_HANDLE, + }; + + static FoxBCRegister RegFlagToReg(FoxRegisterFlag reg_flag); + static FoxRegisterFlag RegToRegFlag(FoxBCRegister reg); + + static const char* GetRegisterName(FoxBCRegister reg); + + FoxMPPagedArray mBytecode {}; + + enum VarDeclareMode + { + DECLARE_DEFAULT, + DECLARE_NO_EMIT, + }; + + +private: + void EmitBlock(FoxAstBlock* block); + void EmitFunction(FoxAstFunctionDecl* function); + void DoFunctionCall(FoxAstFunctionCall* call); + FoxBytecodeVarHandle* DoVarDeclare(FoxAstVarDecl* decl, VarDeclareMode mode = DECLARE_DEFAULT); + void EmitAssign(FoxAstAssign* assign); + FoxBytecodeVarHandle* DefineAndFetchParam(FoxAstNode* param_decl_node); + FoxBytecodeVarHandle* DefineReturnVar(FoxAstVarDecl* decl); + + FoxBCRegister EmitVarFetch(FoxAstVarRef* ref, RhsMode mode); + + void DoLoad(uint32 stack_offset, FoxBCRegister output_reg, bool force_absolute = false); + void DoSaveInt32(uint32 stack_offset, uint32 value, bool force_absolute = false); + void DoSaveReg32(uint32 stack_offset, FoxBCRegister reg, bool force_absolute = false); + + void EmitPush32(uint32 value); + void EmitPush32r(FoxBCRegister reg); + + void EmitPop32(FoxBCRegister output_reg); + + void EmitLoad32(int offset, FoxBCRegister output_reg); + void EmitLoadAbsolute32(uint32 position, FoxBCRegister output_reg); + + void EmitSave32(int16 offset, uint32 value); + void EmitSaveReg32(int16 offset, FoxBCRegister reg); + + void EmitSaveAbsolute32(uint32 offset, uint32 value); + void EmitSaveAbsoluteReg32(uint32 offset, FoxBCRegister reg); + + void EmitJumpRelative(uint16 offset); + void EmitJumpAbsolute(uint32 position); + void EmitJumpAbsoluteReg32(FoxBCRegister reg); + void EmitJumpCallAbsolute(uint32 position); + void EmitJumpReturnToCaller(); + void EmitJumpCallExternal(FoxHash hashed_name); + + void EmitMoveInt32(FoxBCRegister reg, uint32 value); + + void EmitParamsStart(); + void EmitType(FoxValue::ValueType type); + + uint32 EmitDataString(char* str, uint16 length); + + FoxBCRegister EmitBinop(FoxAstBinop* binop, FoxBytecodeVarHandle* handle); + + FoxBCRegister EmitRhs(FoxAstNode* rhs, RhsMode mode, FoxBytecodeVarHandle* handle); + + FoxBCRegister EmitLiteralInt(FoxAstLiteral* literal, RhsMode mode, FoxBytecodeVarHandle* handle); + FoxBCRegister EmitLiteralString(FoxAstLiteral* literal, RhsMode mode, FoxBytecodeVarHandle* handle); + + + void WriteOp(uint8 base_op, uint8 spec_op); + void Write16(uint16 value); + void Write32(uint32 value); + + FoxBCRegister FindFreeRegister(); + + FoxBytecodeVarHandle* FindVarHandle(FoxHash hashed_name); + FoxBytecodeFunctionHandle* FindFunctionHandle(FoxHash hashed_name); + + void PrintBytecode(); + + void MarkRegisterUsed(FoxBCRegister reg); + void MarkRegisterFree(FoxBCRegister reg); + +public: + FoxMPPagedArray VarHandles; + std::vector FunctionHandles; + +private: + FoxRegisterFlag mRegsInUse = FX_REGFLAG_NONE; + + int64 mStackOffset = 0; + uint32 mStackSize = 0; + + uint16 mScopeIndex = 0; +}; + +class FoxBCPrinter +{ +public: + FoxBCPrinter(FoxMPPagedArray& bytecode) + { + mBytecode = bytecode; + mBytecode.DoNotDestroy = true; + } + + void Print(); + void PrintOp(); + + +private: + uint16 Read16(); + uint32 Read32(); + + void DoPush(char* s, uint8 op_base, uint8 op_spec); + void DoPop(char* s, uint8 op_base, uint8 op_spec); + void DoLoad(char* s, uint8 op_base, uint8 op_spec); + void DoArith(char* s, uint8 op_base, uint8 op_spec); + void DoSave(char* s, uint8 op_base, uint8 op_spec); + void DoJump(char* s, uint8 op_base, uint8 op_spec); + void DoData(char* s, uint8 op_base, uint8 op_spec); + void DoType(char* s, uint8 op_base, uint8 op_spec); + void DoMove(char* s, uint8 op_base, uint8 op_spec); + +private: + uint32 mBytecodeIndex = 0; + FoxMPPagedArray mBytecode; +}; + + +/////////////////////////////////////////// +// Bytecode VM +/////////////////////////////////////////// + +struct FoxVMCallFrame +{ + uint32 StartStackIndex = 0; +}; + +class FoxVM +{ +public: + FoxVM() = default; + + void Start(FoxMPPagedArray&& bytecode) + { + mBytecode = std::move(bytecode); + mPushedTypes.Create(64); + + Stack = FX_SCRIPT_ALLOC_MEMORY(uint8, 1024); + // mStackOffset = 0; + Registers[FX_REG_SP] = 0; + memset(Registers, 0, sizeof(Registers)); + + while (mPC < mBytecode.Size()) { + ExecuteOp(); + } + + PrintRegisters(); + } + + void PrintRegisters(); + + void Push16(uint16 value); + void Push32(uint32 value); + + uint32 Pop32(); + +private: + void ExecuteOp(); + + void DoPush(uint8 op_base, uint8 op_spec); + void DoPop(uint8 op_base, uint8 op_spec); + void DoLoad(uint8 op_base, uint8 op_spec); + void DoArith(uint8 op_base, uint8 op_spec); + void DoSave(uint8 op_base, uint8 op_spec); + void DoJump(uint8 op_base, uint8 op_spec); + void DoData(uint8 op_base, uint8 op_spec); + void DoType(uint8 op_base, uint8 op_spec); + void DoMove(uint8 op_base, uint8 op_spec); + + uint16 Read16(); + uint32 Read32(); + + FoxVMCallFrame& PushCallFrame(); + FoxVMCallFrame* GetCurrentCallFrame(); + void PopCallFrame(); + + FoxExternalFunc* FindExternalFunction(FoxHash hashed_name); + +public: + // NONE, X0, X1, X2, X3, RA, XR, SP + int32 Registers[FX_REG_SIZE]; + + uint8* Stack = nullptr; + + std::vector mExternalFuncs; + + FoxMPPagedArray mBytecode; + +private: + uint32 mPC = 0; + + + bool mIsInCallFrame = false; + + FoxVMCallFrame mCallFrames[8]; + int mCallFrameIndex = 0; + + bool mIsInParams = false; + FoxMPPagedArray mPushedTypes; + + FoxValue::ValueType mCurrentType = FoxValue::NONETYPE; +}; + +//////////////////////////////////////////////// +// Script Interpreter +//////////////////////////////////////////////// +#if 0 +class FoxInterpreter +{ +public: + FoxInterpreter() = default; + + void PushScope(); + void PopScope(); + + FoxVar* FindVar(FoxHash hashed_name); + FoxFunction* FindFunction(FoxHash hashed_name); + FoxExternalFunc* FindExternalFunction(FoxHash hashed_name); + + /** + * @brief Evaluates and gets the immediate value if `value` is a reference, or returns the value if it is already immediate. + * @param value The value to query from + * @return the immediate(literal) value + */ + const FoxValue& GetImmediateValue(const FoxValue& value); + + void DefineExternalVar(const char* type, const char* name, const FoxValue& value); + +private: + friend class FoxConfigScript; + void Create(FoxAstBlock* root_block); + + void Visit(FoxAstNode* node); + + void Interpret(); + + FoxValue VisitExternalCall(FoxAstFunctionCall* call, FoxExternalFunc& func); + FoxValue VisitFunctionCall(FoxAstFunctionCall* call); + void VisitAssignment(FoxAstAssign* assign); + FoxValue VisitRhs(FoxAstNode* node); + + bool CheckExternalCallArgs(FoxAstFunctionCall* call, FoxExternalFunc& func); + + + +private: + FoxAstNode* mRootBlock = nullptr; + + bool mInCommandMode = false; + + std::vector mExternalFuncs; + + FoxMPPagedArray mScopes; + FoxScope* mCurrentScope = nullptr; +}; + +#endif +///////////////////////////////////// +// Bytecode to x86 Transpiler +///////////////////////////////////// + + +class FoxTranspilerX86 +{ +public: + FoxTranspilerX86(FoxMPPagedArray& bytecode) + { + mBytecode = bytecode; + mBytecode.DoNotDestroy = true; + } + + void Print(); + void PrintOp(); + + +private: + uint16 Read16(); + uint32 Read32(); + + void DoPush(char* s, uint8 op_base, uint8 op_spec); + void DoPop(char* s, uint8 op_base, uint8 op_spec); + void DoLoad(char* s, uint8 op_base, uint8 op_spec); + void DoArith(char* s, uint8 op_base, uint8 op_spec); + void DoSave(char* s, uint8 op_base, uint8 op_spec); + void DoJump(char* s, uint8 op_base, uint8 op_spec); + void DoData(char* s, uint8 op_base, uint8 op_spec); + void DoType(char* s, uint8 op_base, uint8 op_spec); + void DoMove(char* s, uint8 op_base, uint8 op_spec); + + + void StrOut(const char* fmt, ...); + +private: + uint32 mBytecodeIndex = 0; + + uint32 mSizePushedInFunction = 0; + bool mIsInFunction = false; + + int mTextIndent = 0; + + FoxMPPagedArray mBytecode; +}; + + +//////////////////////////////////////////// +// IR Emitter +//////////////////////////////////////////// + + +#include "FoxScriptBytecode.hpp" + +class FoxIREmitter +{ +public: + FoxIREmitter() = default; + + void BeginEmitting(FoxAstNode* node); + void Emit(FoxAstNode* node); + + enum RhsMode + { + RHS_FETCH_TO_REGISTER, + + /** + * @brief Pushes the value to the stack, assuming that the value does not exist yet. + */ + RHS_DEFINE_IN_MEMORY, + + RHS_ASSIGN_TO_HANDLE, + }; + + static const char* GetRegisterName(FoxIRRegister reg); + + FoxMPPagedArray mBytecode {}; + + enum VarDeclareMode + { + DECLARE_DEFAULT, + DECLARE_NO_EMIT, + }; + + +private: + void EmitBlock(FoxAstBlock* block); + void EmitFunction(FoxAstFunctionDecl* function); + void DoFunctionCall(FoxAstFunctionCall* call); + FoxBytecodeVarHandle* DoVarDeclare(FoxAstVarDecl* decl, VarDeclareMode mode = DECLARE_DEFAULT); + void EmitAssign(FoxAstAssign* assign); + FoxBytecodeVarHandle* DefineAndFetchParam(FoxAstNode* param_decl_node); + FoxBytecodeVarHandle* DefineReturnVar(FoxAstVarDecl* decl); + + FoxIRRegister EmitVarFetch(FoxAstVarRef* ref, RhsMode mode); + + uint16 GetSizeOfType(FoxTokenizer::Token* type); + + void DoLoad(uint32 stack_offset, FoxIRRegister output_reg, bool force_absolute = false); + void DoSaveInt32(uint32 stack_offset, uint32 value, bool force_absolute = false); + void DoSaveReg32(uint32 stack_offset, FoxIRRegister reg, bool force_absolute = false); + + void EmitPush32(uint32 value); + void EmitPush32r(FoxIRRegister reg); + + void EmitStackAlloc(uint16 size); + + void EmitPop32(FoxIRRegister output_reg); + + void EmitLoad32(int offset, FoxIRRegister output_reg); + void EmitLoadAbsolute32(uint32 position, FoxIRRegister output_reg); + + void EmitSave32(int16 offset, uint32 value); + void EmitSaveReg32(int16 offset, FoxIRRegister reg); + + void EmitSaveAbsolute32(uint32 offset, uint32 value); + void EmitSaveAbsoluteReg32(uint32 offset, FoxIRRegister reg); + + void EmitJumpRelative(uint16 offset); + void EmitJumpAbsolute(uint32 position); + void EmitJumpAbsoluteReg32(FoxIRRegister reg); + void EmitJumpCallAbsolute(uint32 position); + void EmitJumpReturnToCaller(); + void EmitJumpCallExternal(FoxHash hashed_name); + + void EmitVariableGetInt32(uint16 var_index, FoxIRRegister dest_reg); + void EmitVariableSetInt32(uint16 var_index, int32 value); + void EmitVariableSetReg32(uint16 var_index, FoxIRRegister reg); + + void EmitMoveInt32(FoxIRRegister reg, uint32 value); + + void EmitParamsStart(); + void EmitType(FoxValue::ValueType type); + + uint32 EmitDataString(char* str, uint16 length); + + FoxIRRegister EmitBinop(FoxAstBinop* binop, FoxBytecodeVarHandle* handle); + + FoxIRRegister EmitRhs(FoxAstNode* rhs, RhsMode mode, FoxBytecodeVarHandle* handle); + + FoxIRRegister EmitLiteralInt(FoxAstLiteral* literal, RhsMode mode, FoxBytecodeVarHandle* handle); + FoxIRRegister EmitLiteralString(FoxAstLiteral* literal, RhsMode mode, FoxBytecodeVarHandle* handle); + + void EmitMarker(IrSpecMarker spec); + + void WriteOp(uint8 base_op, uint8 spec_op); + void Write16(uint16 value); + void Write32(uint32 value); + + FoxIRRegister FindFreeReg32(); + FoxIRRegister FindFreeReg64(); + + FoxBytecodeVarHandle* FindVarHandle(FoxHash hashed_name); + FoxBytecodeFunctionHandle* FindFunctionHandle(FoxHash hashed_name); + + void PrintBytecode(); + + void MarkRegisterUsed(FoxIRRegister reg); + void MarkRegisterFree(FoxIRRegister reg); + +public: + FoxMPPagedArray VarHandles; + std::vector FunctionHandles; + +private: + FoxRegisterFlag mRegsInUse = FX_REGFLAG_NONE; + + int64 mStackOffset = 0; + uint32 mStackSize = 0; + + uint16 mVarsInScope = 0; + + uint16 mScopeIndex = 0; +}; + + +class FoxIRPrinter +{ +public: + FoxIRPrinter(FoxMPPagedArray& bytecode) + { + mBytecode = bytecode; + mBytecode.DoNotDestroy = true; + } + + void Print(); + void PrintOp(); + + +private: + uint16 Read16(); + uint32 Read32(); + + void DoPush(char* s, uint8 op_base, uint8 op_spec); + void DoPop(char* s, uint8 op_base, uint8 op_spec); + void DoLoad(char* s, uint8 op_base, uint8 op_spec); + void DoArith(char* s, uint8 op_base, uint8 op_spec); + void DoSave(char* s, uint8 op_base, uint8 op_spec); + void DoJump(char* s, uint8 op_base, uint8 op_spec); + void DoData(char* s, uint8 op_base, uint8 op_spec); + void DoType(char* s, uint8 op_base, uint8 op_spec); + void DoMove(char* s, uint8 op_base, uint8 op_spec); + void DoMarker(char* s, uint8 op_base, uint8 op_spec); + void DoVariable(char* s, uint8 op_base, uint8 op_spec); + +private: + uint32 mBytecodeIndex = 0; + FoxMPPagedArray mBytecode; +}; diff --git a/FxScriptBytecode.hpp b/FoxScriptBytecode.hpp similarity index 86% rename from FxScriptBytecode.hpp rename to FoxScriptBytecode.hpp index 99b04f0..0662e07 100644 --- a/FxScriptBytecode.hpp +++ b/FoxScriptBytecode.hpp @@ -1,6 +1,6 @@ #pragma once -#include "FxScriptUtil.hpp" +#include "FoxScriptUtil.hpp" /* @@ -96,12 +96,17 @@ enum IrBase : uint8 IrBase_Data, IrBase_Type, IrBase_Move, + IrBase_Marker, + + IrBase_Variable, }; enum IrSpecPush : uint8 { IrSpecPush_Int32 = 1, // PUSH32 [imm] IrSpecPush_Reg32, // PUSH32r [%r32] + + IrSpecPush_StackAlloc, }; enum IrSpecPop : uint8 @@ -143,7 +148,6 @@ enum IrSpecJump : uint8 enum IrSpecData : uint8 { IrSpecData_String = 1, - IrSpecData_ParamsStart, }; enum IrSpecType : uint8 @@ -156,3 +160,20 @@ enum IrSpecMove : uint8 { IrSpecMove_Int32 = 1, }; + +enum IrSpecMarker : uint8 +{ + // Function frame ops + IrSpecMarker_FrameBegin = 1, + IrSpecMarker_FrameEnd, + + IrSpecMarker_ParamsBegin, + +}; + +enum IrSpecVariable : uint8 +{ + IrSpecVariable_Set_Int32 = 1, + IrSpecVariable_Set_Reg32, + IrSpecVariable_Get_Int32, +}; diff --git a/FxScriptUtil.hpp b/FoxScriptUtil.hpp similarity index 74% rename from FxScriptUtil.hpp rename to FoxScriptUtil.hpp index 2acb640..d99e872 100644 --- a/FxScriptUtil.hpp +++ b/FoxScriptUtil.hpp @@ -1,8 +1,7 @@ #pragma once -#include #include - +#include #include // #include @@ -13,25 +12,25 @@ #ifdef FX_SCRIPT_USE_MEMPOOL -#include "FxMemPool.hpp" +#include "FoxMemPool.hpp" -#define FX_SCRIPT_ALLOC_MEMORY(ptrtype_, size_) FxMemPool::Alloc(size_) -#define FX_SCRIPT_ALLOC_NODE(nodetype_) FxMemPool::Alloc(sizeof(nodetype_)) -#define FX_SCRIPT_FREE(ptrtype_, ptr_) FxMemPool::Free(ptr_) +#define FX_SCRIPT_ALLOC_MEMORY(ptrtype_, size_) FoxMemPool::Alloc(size_) +#define FX_SCRIPT_ALLOC_NODE(nodetype_) FoxMemPool::Alloc(sizeof(nodetype_)) +#define FX_SCRIPT_FREE(ptrtype_, ptr_) FoxMemPool::Free(ptr_) #else // #define FX_SCRIPT_ALLOC_MEMORY(ptrtype_, size_) new ptrtype_[size_] -#define FX_SCRIPT_ALLOC_MEMORY(ptrtype_, size_) FxScriptAllocMemory(size_) -#define FX_SCRIPT_ALLOC_NODE(nodetype_) FxScriptAllocMemory(sizeof(nodetype_)) -#define FX_SCRIPT_FREE(ptrtype_, ptr_) FxScriptFreeMemory(ptr_) +#define FX_SCRIPT_ALLOC_MEMORY(ptrtype_, size_) FoxAllocMemory(size_) +#define FX_SCRIPT_ALLOC_NODE(nodetype_) FoxAllocMemory(sizeof(nodetype_)) +#define FX_SCRIPT_FREE(ptrtype_, ptr_) FoxFreeMemory(ptr_) #include #endif template -T* FxScriptAllocMemory(size_t size) +T* FoxAllocMemory(size_t size) { T* ptr = reinterpret_cast(malloc(size)); if constexpr (std::is_constructible_v) { @@ -42,7 +41,7 @@ T* FxScriptAllocMemory(size_t size) } template -void FxScriptFreeMemory(T* ptr) +void FoxFreeMemory(T* ptr) { if constexpr (std::is_destructible_v) { ptr->~T(); @@ -76,7 +75,7 @@ typedef double float64; ///////////////////////////// -class FxUtil +class FoxUtil { public: static FILE* FileOpen(const char* path, const char* mode) @@ -93,14 +92,14 @@ class FxUtil #define FX_HASH_FNV1A_SEED 0x811C9DC5 #define FX_HASH_FNV1A_PRIME 0x01000193 -using FxHash = uint32; +using FoxHash = uint32; /** * Hashes a string at compile time using FNV-1a. * * Source to algorithm: http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param */ -inline constexpr FxHash FxHashStr(const char *str) +inline constexpr FoxHash FoxHashStr(const char* str) { uint32 hash = FX_HASH_FNV1A_SEED; @@ -124,7 +123,7 @@ inline constexpr FxHash FxHashStr(const char *str) #endif template -void FxPanic(const char* const module, const char* fmt, T first, Types... items) +void FoxPanic(const char* const module, const char* fmt, T first, Types... items) { // printf(fmt, items...); ((std::cout << items), ...); @@ -138,7 +137,7 @@ void FxPanic(const char* const module, const char* fmt, T first, Types... items) * * Source to algorithm: http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-param */ -inline constexpr FxHash FxHashStr(const char *str, uint32 length) +inline constexpr FoxHash FoxHashStr(const char* str, uint32 length) { uint32 hash = FX_HASH_FNV1A_SEED; diff --git a/FxTokenizer.hpp b/FoxTokenizer.hpp similarity index 91% rename from FxTokenizer.hpp rename to FoxTokenizer.hpp index 0c588d8..31e9c92 100644 --- a/FxTokenizer.hpp +++ b/FoxTokenizer.hpp @@ -1,14 +1,14 @@ #pragma once -#include "FxScriptUtil.hpp" -#include "FxMPPagedArray.hpp" +#include "FoxMPPagedArray.hpp" +#include "FoxScriptUtil.hpp" +#include #include #include -#include #include -class FxTokenizer +class FoxTokenizer { private: public: @@ -25,7 +25,8 @@ class FxTokenizer }; - enum TokenType { + enum TokenType + { Unknown, Identifier, @@ -60,33 +61,23 @@ class FxTokenizer static const char* GetTypeName(TokenType type) { const char* type_names[] = { - "Unknown", - "Identifier", + "Unknown", "Identifier", - "String", - "Integer", - "Float", + "String", "Integer", "Float", "Equals", - "LParen", - "RParen", + "LParen", "RParen", - "LBracket", - "RBracket", + "LBracket", "RBracket", - "LBrace", - "RBrace", + "LBrace", "RBrace", - "Plus", - "Dollar", - "Minus", + "Plus", "Dollar", "Minus", "Question", - "Dot", - "Comma", - "Semicolon", + "Dot", "Comma", "Semicolon", "DocComment", }; @@ -98,10 +89,11 @@ class FxTokenizer return type_names[type]; } - enum class IsNumericResult { + enum class IsNumericResult + { NaN, Integer, - Fractional + Frfunctional }; struct Token @@ -109,14 +101,14 @@ class FxTokenizer char* Start = nullptr; char* End = nullptr; - FxHash Hash = 0; + FoxHash Hash = 0; TokenType Type = TokenType::Unknown; uint32 Length = 0; uint16 FileColumn = 0; uint32 FileLine = 0; - void Print(bool no_newline=false) const + void Print(bool no_newline = false) const { printf("Token: (T:%-10s) {%.*s} %c", GetTypeName(Type), Length, Start, (no_newline) ? ' ' : '\n'); } @@ -136,7 +128,7 @@ class FxTokenizer char* str = static_cast(FX_SCRIPT_ALLOC_MEMORY(char, (Length + 1))); if (str == nullptr) { - FxPanic("FxTokenizer", "Error allocating heap string!", 0); + FoxPanic("FoxTokenizer", "Error allocating heap string!", 0); return nullptr; } @@ -146,12 +138,12 @@ class FxTokenizer return str; } - FxHash GetHash() + FoxHash GetHash() { if (Hash != 0) { return Hash; } - return (Hash = FxHashStr(Start, Length)); + return (Hash = FoxHashStr(Start, Length)); } IsNumericResult IsNumeric() const @@ -163,13 +155,13 @@ class FxTokenizer for (int i = 0; i < Length; i++) { ch = Start[i]; - // If there is a number preceding the dot then we are a fractional + // If there is a number preceding the dot then we are a frfunctional if (ch == '.' && result != IsNumericResult::NaN) { - result = IsNumericResult::Fractional; + result = IsNumericResult::Frfunctional; continue; } - if ((ch >= '0' && ch <= '9') ) { + if ((ch >= '0' && ch <= '9')) { // If no numbers have been found yet then set to integer if (result == IsNumericResult::NaN) { result = IsNumericResult::Integer; @@ -188,7 +180,7 @@ class FxTokenizer int64 ToInt() const { char buffer[32]; - + std::strncpy(buffer, Start, Length); buffer[Length] = 0; @@ -206,7 +198,7 @@ class FxTokenizer return strtof(buffer, &end); } - bool operator == (const char* str) const + bool operator==(const char* str) const { return !strncmp(Start, str, Length); } @@ -224,10 +216,9 @@ class FxTokenizer } }; - FxTokenizer() = delete; + FoxTokenizer() = delete; - FxTokenizer(char* data, uint32 buffer_size) - : mData(data), mDataEnd(data + buffer_size), mStartOfLine(data) + FoxTokenizer(char* data, uint32 buffer_size) : mData(data), mDataEnd(data + buffer_size), mStartOfLine(data) { } @@ -242,7 +233,7 @@ class FxTokenizer switch (is_numeric) { case IsNumericResult::Integer: return TokenType::Integer; - case IsNumericResult::Fractional: + case IsNumericResult::Frfunctional: return TokenType::Float; case IsNumericResult::NaN: break; @@ -366,7 +357,8 @@ class FxTokenizer } // Skip spaces and tabs - while ((ch = *(data)) && (ch == ' ' || ch == '\t')) ++data; + while ((ch = *(data)) && (ch == ' ' || ch == '\t')) + ++data; // Check if this is a string if (ch != '"') { @@ -429,7 +421,7 @@ class FxTokenizer void IncludeFile(char* path) { - FILE* fp = FxUtil::FileOpen(path, "rb"); + FILE* fp = FoxUtil::FileOpen(path, "rb"); if (!fp) { printf("Could not open include file '%s'\n", path); return; @@ -451,7 +443,7 @@ class FxTokenizer // Restore back to previous state RestoreState(); - //FxMemPool::Free(include_data); + // FoxMemPool::Free(include_data); } void TryReadInternalCall() @@ -619,7 +611,7 @@ class FxTokenizer return (token.Start - mData); } - FxMPPagedArray& GetTokens() + FoxMPPagedArray& GetTokens() { return mTokens; } @@ -642,7 +634,6 @@ class FxTokenizer mFileLine = mSavedState.FileLine; mStartOfLine = mSavedState.StartOfLine; - } private: @@ -662,5 +653,5 @@ class FxTokenizer uint32 mFileLine = 0; char* mStartOfLine = nullptr; - FxMPPagedArray mTokens; + FoxMPPagedArray mTokens; }; diff --git a/FxScript.hpp b/FxScript.hpp deleted file mode 100644 index dcd3d86..0000000 --- a/FxScript.hpp +++ /dev/null @@ -1,1178 +0,0 @@ -#pragma once - -#include "FxMPPagedArray.hpp" -#include "FxTokenizer.hpp" - -#include - -#define FX_SCRIPT_VERSION_MAJOR 0 -#define FX_SCRIPT_VERSION_MINOR 3 -#define FX_SCRIPT_VERSION_PATCH 1 - -#define FX_SCRIPT_VAR_RETURN_VAL "__ReturnVal__" - - -struct FxAstVarRef; -struct FxScriptScope; -struct FxScriptAction; - -struct FxScriptValue -{ - static FxScriptValue None; - - enum ValueType : uint16 - { - NONETYPE = 0x00, - INT = 0x01, - FLOAT = 0x02, - STRING = 0x04, - VEC3 = 0x08, - REF = 0x10 - }; - - ValueType Type = NONETYPE; - - union - { - int ValueInt = 0; - float ValueFloat; - float ValueVec3[3]; - char* ValueString; - - FxAstVarRef* ValueRef; - }; - - FxScriptValue() - { - } - - explicit FxScriptValue(ValueType type, int value) : Type(type), ValueInt(value) - { - } - - explicit FxScriptValue(ValueType type, float value) : Type(type), ValueFloat(value) - { - } - - FxScriptValue(const FxScriptValue& other) - { - Type = other.Type; - if (other.Type == INT) { - ValueInt = other.ValueInt; - } - else if (other.Type == FLOAT) { - ValueFloat = other.ValueFloat; - } - else if (other.Type == STRING) { - ValueString = other.ValueString; - } - else if (other.Type == REF) { - ValueRef = other.ValueRef; - } - } - - void Print() const - { - printf("[Value: "); - if (Type == NONETYPE) { - printf("Null]\n"); - } - else if (Type == INT) { - printf("Int, %d]\n", ValueInt); - } - else if (Type == FLOAT) { - printf("Float, %f]\n", ValueFloat); - } - else if (Type == STRING) { - printf("String, %s]\n", ValueString); - } - else if (Type == REF) { - printf("Ref, %p]\n", ValueRef); - } - } - - inline bool IsNumber() - { - return (Type == INT || Type == FLOAT); - } - - inline bool IsRef() - { - return (Type == REF); - } -}; - -enum FxAstType -{ - FX_AST_LITERAL, - // FX_AST_NAME, - - FX_AST_BINOP, - FX_AST_UNARYOP, - FX_AST_BLOCK, - - // Variables - FX_AST_VARREF, - FX_AST_VARDECL, - FX_AST_ASSIGN, - - // Actions - FX_AST_ACTIONDECL, - FX_AST_ACTIONCALL, - FX_AST_RETURN, - - FX_AST_DOCCOMMENT, - - FX_AST_COMMANDMODE, -}; - -struct FxAstNode -{ - FxAstType NodeType; -}; - - -struct FxAstLiteral : public FxAstNode -{ - FxAstLiteral() - { - this->NodeType = FX_AST_LITERAL; - } - - // FxTokenizer::Token* Token = nullptr; - FxScriptValue Value; -}; - -struct FxAstBinop : public FxAstNode -{ - FxAstBinop() - { - this->NodeType = FX_AST_BINOP; - } - - FxTokenizer::Token* OpToken = nullptr; - FxAstNode* Left = nullptr; - FxAstNode* Right = nullptr; -}; - -struct FxAstBlock : public FxAstNode -{ - FxAstBlock() - { - this->NodeType = FX_AST_BLOCK; - } - - std::vector Statements; -}; - -struct FxAstVarRef : public FxAstNode -{ - FxAstVarRef() - { - this->NodeType = FX_AST_VARREF; - } - - FxTokenizer::Token* Name = nullptr; - FxScriptScope* Scope = nullptr; -}; - -struct FxAstAssign : public FxAstNode -{ - FxAstAssign() - { - this->NodeType = FX_AST_ASSIGN; - } - - FxAstVarRef* Var = nullptr; - // FxScriptValue Value; - FxAstNode* Rhs = nullptr; -}; - -struct FxAstVarDecl : public FxAstNode -{ - FxAstVarDecl() - { - this->NodeType = FX_AST_VARDECL; - } - - FxTokenizer::Token* Name = nullptr; - FxTokenizer::Token* Type = nullptr; - FxAstAssign* Assignment = nullptr; - - /// Ignore the scope that the variable is declared in, force it to be global. - bool DefineAsGlobal = false; -}; - -struct FxAstDocComment : public FxAstNode -{ - FxAstDocComment() - { - this->NodeType = FX_AST_DOCCOMMENT; - } - - FxTokenizer::Token* Comment; -}; - -struct FxAstActionDecl : public FxAstNode -{ - FxAstActionDecl() - { - this->NodeType = FX_AST_ACTIONDECL; - } - - FxTokenizer::Token* Name = nullptr; - FxAstVarDecl* ReturnVar = nullptr; - FxAstBlock* Params = nullptr; - FxAstBlock* Block = nullptr; - - std::vector DocComments; -}; - -struct FxAstCommandMode : public FxAstNode -{ - FxAstCommandMode() - { - this->NodeType = FX_AST_COMMANDMODE; - } - - FxAstNode* Node = nullptr; -}; - -struct FxAstActionCall : public FxAstNode -{ - FxAstActionCall() - { - this->NodeType = FX_AST_ACTIONCALL; - } - - FxScriptAction* Action = nullptr; - FxHash HashedName = 0; - std::vector Params {}; // FxAstLiteral or FxAstVarRef -}; - -struct FxAstReturn : public FxAstNode -{ - FxAstReturn() - { - this->NodeType = FX_AST_RETURN; - } -}; - -/** - * @brief Data is accessible from a label, such as a variable or an action. - */ -struct FxScriptLabelledData -{ - FxHash HashedName = 0; - FxTokenizer::Token* Name = nullptr; - - FxScriptScope* Scope = nullptr; -}; - -struct FxScriptAction : public FxScriptLabelledData -{ - FxScriptAction(FxTokenizer::Token* name, FxScriptScope* scope, FxAstBlock* block, FxAstActionDecl* declaration) - { - HashedName = name->GetHash(); - Name = name; - Scope = scope; - Block = block; - Declaration = declaration; - } - - FxAstActionDecl* Declaration = nullptr; - FxAstBlock* Block = nullptr; -}; - -struct FxScriptVar : public FxScriptLabelledData -{ - FxTokenizer::Token* Type = nullptr; - FxScriptValue Value; - - bool IsExternal = false; - - void Print() const - { - printf("[Var] Type: %.*s, Name: %.*s (Hash:%u)", Type->Length, Type->Start, Name->Length, Name->Start, Name->GetHash()); - Value.Print(); - } - - FxScriptVar() - { - } - - FxScriptVar(FxTokenizer::Token* type, FxTokenizer::Token* name, FxScriptScope* scope, bool is_external = false) : Type(type) - { - this->HashedName = name->GetHash(); - this->Name = name; - this->Scope = scope; - IsExternal = is_external; - } - - FxScriptVar(const FxScriptVar& other) - { - HashedName = other.HashedName; - Type = other.Type; - Name = other.Name; - Value = other.Value; - IsExternal = other.IsExternal; - } - - FxScriptVar& operator=(FxScriptVar&& other) noexcept - { - HashedName = other.HashedName; - Type = other.Type; - Name = other.Name; - Value = other.Value; - IsExternal = other.IsExternal; - - Name = nullptr; - Type = nullptr; - HashedName = 0; - - return *this; - } - - ~FxScriptVar() - { - if (!IsExternal) { - return; - } - - // Free tokens allocated by external variables - if (Type && Type->Start) { - FX_SCRIPT_FREE(char, Type->Start); - } - - if (this->Name && this->Name->Start) { - FX_SCRIPT_FREE(char, this->Name->Start); - } - } -}; - -class FxScriptVM; - - -struct FxScriptExternalFunc -{ - // using FuncType = void (*)(FxScriptInterpreter& interpreter, std::vector& params, FxScriptValue* return_value); - - using FuncType = void (*)(FxScriptVM* vm, std::vector& params, FxScriptValue* return_value); - - FxHash HashedName = 0; - FuncType Function = nullptr; - - std::vector ParameterTypes; - bool IsVariadic = false; -}; - -struct FxScriptScope -{ - FxMPPagedArray Vars; - FxMPPagedArray Actions; - - FxScriptScope* Parent = nullptr; - - // This points to the return value for the current scope. If an action returns a value, - // this will be set to the variable that holds its value. This is interpreter only. - FxScriptVar* ReturnVar = nullptr; - - void PrintAllVarsInScope() - { - puts("\n=== SCOPE ==="); - for (FxScriptVar& var : Vars) { - var.Print(); - } - } - - FxScriptVar* FindVarInScope(FxHash hashed_name) - { - return FindInScope(hashed_name, Vars); - } - - FxScriptAction* FindActionInScope(FxHash hashed_name) - { - return FindInScope(hashed_name, Actions); - } - - template - requires std::is_base_of_v - T* FindInScope(FxHash hashed_name, const FxMPPagedArray& buffer) - { - for (T& var : buffer) { - if (var.HashedName == hashed_name) { - return &var; - } - } - - return nullptr; - } -}; - -// class FxScriptInterpreter; - -class FxConfigScript -{ - using Token = FxTokenizer::Token; - using TT = FxTokenizer::TokenType; - -public: - FxConfigScript() = default; - - void LoadFile(const char* path); - - void PushScope(); - void PopScope(); - - FxScriptVar* FindVar(FxHash hashed_name); - - FxScriptAction* FindAction(FxHash hashed_name); - FxScriptExternalFunc* FindExternalAction(FxHash hashed_name); - - FxAstNode* TryParseKeyword(FxAstBlock* parent_block); - - FxAstAssign* TryParseAssignment(FxTokenizer::Token* var_name); - - FxScriptValue ParseValue(); - - FxAstActionDecl* ParseActionDeclare(); - - FxAstNode* ParseRhs(); - FxAstActionCall* ParseActionCall(); - - /** - * @brief Declares a variable for internal uses as if it was declared in the script. - * @param name Name of the variable - * @param type The name of the type - * @param scope The scope the variable will be declared in - * @return - */ - FxAstVarDecl* InternalVarDeclare(FxTokenizer::Token* name_token, FxTokenizer::Token* type_token, FxScriptScope* scope = nullptr); - FxAstVarDecl* ParseVarDeclare(FxScriptScope* scope = nullptr); - - FxAstBlock* ParseBlock(); - - FxAstNode* ParseStatement(FxAstBlock* parent_block); - FxAstNode* ParseStatementAsCommand(FxAstBlock* parent_block); - - FxAstBlock* Parse(); - - /** - * @brief Parses and executes a script. - * @param interpreter The interpreter to execute with - */ - void Execute(FxScriptVM& vm); - - /** - * @brief Executes a command on a script. Defaults to parsing with command style syntax. - * @param command The command to execute on the script. - * @return If the command has been executed - */ - // bool ExecuteUserCommand(const char* command, FxScriptInterpreter& interpreter); - - Token& GetToken(int offset = 0); - Token& EatToken(TT token_type); - - void RegisterExternalFunc(FxHash func_name, std::vector param_types, FxScriptExternalFunc::FuncType func, - bool is_variadic); - - void DefineExternalVar(const char* type, const char* name, const FxScriptValue& value); - -private: - template - requires std::is_base_of_v - T* FindLabelledData(FxHash hashed_name, FxMPPagedArray& buffer) - { - FxScriptScope* scope = mCurrentScope; - - while (scope) { - T* var = scope->FindInScope(hashed_name, buffer); - if (var) { - return var; - } - - scope = scope->Parent; - } - - return nullptr; - } - - void DefineDefaultExternalFunctions(); - - Token* CreateTokenFromString(FxTokenizer::TokenType type, const char* text); - void CreateInternalVariableTokens(); - -private: - FxMPPagedArray mScopes; - FxScriptScope* mCurrentScope; - - std::vector mExternalFuncs; - - std::vector CurrentDocComments; - - FxAstBlock* mRootBlock = nullptr; - - bool mHasErrors = false; - bool mInCommandMode = false; - - char* mFileData; - FxMPPagedArray mTokens = {}; - uint32 mTokenIndex = 0; - - // Name tokens for internal variables - Token* mTokenReturnVar = nullptr; -}; - -////////////////////////////////// -// Script AST Printer -////////////////////////////////// - -class FxAstPrinter -{ -public: - FxAstPrinter(FxAstBlock* root_block) - //: mRootBlock(root_block) - { - } - - void Print(FxAstNode* node, int depth = 0) - { - if (node == nullptr) { - return; - } - - for (int i = 0; i < depth; i++) { - putchar(' '); - putchar(' '); - } - - if (node->NodeType == FX_AST_BLOCK) { - puts("[BLOCK]"); - - FxAstBlock* block = reinterpret_cast(node); - for (FxAstNode* child : block->Statements) { - Print(child, depth + 1); - } - return; - } - else if (node->NodeType == FX_AST_ACTIONDECL) { - FxAstActionDecl* actiondecl = reinterpret_cast(node); - printf("[ACTIONDECL] "); - actiondecl->Name->Print(); - - for (FxAstNode* param : actiondecl->Params->Statements) { - Print(param, depth + 1); - } - - Print(actiondecl->Block, depth + 1); - } - else if (node->NodeType == FX_AST_VARDECL) { - FxAstVarDecl* vardecl = reinterpret_cast(node); - - printf("[VARDECL] "); - vardecl->Name->Print(); - - Print(vardecl->Assignment, depth + 1); - } - else if (node->NodeType == FX_AST_ASSIGN) { - FxAstAssign* assign = reinterpret_cast(node); - - printf("[ASSIGN] "); - - assign->Var->Name->Print(); - Print(assign->Rhs, depth + 1); - } - else if (node->NodeType == FX_AST_ACTIONCALL) { - FxAstActionCall* actioncall = reinterpret_cast(node); - - printf("[ACTIONCALL] "); - if (actioncall->Action == nullptr) { - printf("{defined externally}"); - } - else { - actioncall->Action->Name->Print(true); - } - - printf(" (%zu params)\n", actioncall->Params.size()); - } - else if (node->NodeType == FX_AST_LITERAL) { - FxAstLiteral* literal = reinterpret_cast(node); - - printf("[LITERAL] "); - literal->Value.Print(); - } - else if (node->NodeType == FX_AST_BINOP) { - FxAstBinop* binop = reinterpret_cast(node); - - printf("[BINOP] "); - binop->OpToken->Print(); - - Print(binop->Left, depth + 1); - Print(binop->Right, depth + 1); - } - else if (node->NodeType == FX_AST_COMMANDMODE) { - FxAstCommandMode* command_mode = reinterpret_cast(node); - printf("[COMMANDMODE]\n"); - - Print(command_mode->Node, depth + 1); - } - else if (node->NodeType == FX_AST_RETURN) { - puts("[RETURN]"); - } - else { - puts("[UNKNOWN]"); - } - // else if (node->NodeType == FX_AST_) - } - -public: - // FxAstBlock* mRootBlock = nullptr; -}; - -///////////////////////////////////////////// -// Script Bytecode Emitter -///////////////////////////////////////////// - -enum FxScriptRegister : uint8 -{ - FX_REG_NONE = 0x00, - FX_REG_X0, - FX_REG_X1, - FX_REG_X2, - FX_REG_X3, - - /** - * @brief Return address register. - */ - FX_REG_RA, - - /** - * @brief Register that contains the result of an operation. - */ - FX_REG_XR, - - /** - * @brief Register that contains the stack pointer for the VM. - */ - FX_REG_SP, - - FX_REG_SIZE, -}; - -enum FxScriptRegisterFlag : uint16 -{ - FX_REGFLAG_NONE = 0x00, - FX_REGFLAG_X0 = 0x01, - FX_REGFLAG_X1 = 0x02, - FX_REGFLAG_X2 = 0x04, - FX_REGFLAG_X3 = 0x08, - FX_REGFLAG_RA = 0x10, - FX_REGFLAG_XR = 0x20, -}; - -inline FxScriptRegisterFlag operator|(FxScriptRegisterFlag a, FxScriptRegisterFlag b) -{ - return static_cast(static_cast(a) | static_cast(b)); -} - -inline FxScriptRegisterFlag operator&(FxScriptRegisterFlag a, FxScriptRegisterFlag b) -{ - return static_cast(static_cast(a) & static_cast(b)); -} - -struct FxScriptBytecodeVarHandle -{ - FxHash HashedName = 0; - FxScriptValue::ValueType Type = FxScriptValue::INT; - int64 Offset = 0; - - uint16 SizeOnStack = 4; - uint32 ScopeIndex = 0; -}; - -struct FxScriptBytecodeActionHandle -{ - FxHash HashedName = 0; - uint32 BytecodeIndex = 0; -}; - -class FxScriptBCEmitter -{ -public: - FxScriptBCEmitter() = default; - - void BeginEmitting(FxAstNode* node); - void Emit(FxAstNode* node); - - enum RhsMode - { - RHS_FETCH_TO_REGISTER, - - /** - * @brief Pushes the value to the stack, assuming that the value does not exist yet. - */ - RHS_DEFINE_IN_MEMORY, - - RHS_ASSIGN_TO_HANDLE, - }; - - static FxScriptRegister RegFlagToReg(FxScriptRegisterFlag reg_flag); - static FxScriptRegisterFlag RegToRegFlag(FxScriptRegister reg); - - static const char* GetRegisterName(FxScriptRegister reg); - - FxMPPagedArray mBytecode {}; - - enum VarDeclareMode - { - DECLARE_DEFAULT, - DECLARE_NO_EMIT, - }; - - -private: - void EmitBlock(FxAstBlock* block); - void EmitAction(FxAstActionDecl* action); - void DoActionCall(FxAstActionCall* call); - FxScriptBytecodeVarHandle* DoVarDeclare(FxAstVarDecl* decl, VarDeclareMode mode = DECLARE_DEFAULT); - void EmitAssign(FxAstAssign* assign); - FxScriptBytecodeVarHandle* DefineAndFetchParam(FxAstNode* param_decl_node); - FxScriptBytecodeVarHandle* DefineReturnVar(FxAstVarDecl* decl); - - FxScriptRegister EmitVarFetch(FxAstVarRef* ref, RhsMode mode); - - void DoLoad(uint32 stack_offset, FxScriptRegister output_reg, bool force_absolute = false); - void DoSaveInt32(uint32 stack_offset, uint32 value, bool force_absolute = false); - void DoSaveReg32(uint32 stack_offset, FxScriptRegister reg, bool force_absolute = false); - - void EmitPush32(uint32 value); - void EmitPush32r(FxScriptRegister reg); - - void EmitPop32(FxScriptRegister output_reg); - - void EmitLoad32(int offset, FxScriptRegister output_reg); - void EmitLoadAbsolute32(uint32 position, FxScriptRegister output_reg); - - void EmitSave32(int16 offset, uint32 value); - void EmitSaveReg32(int16 offset, FxScriptRegister reg); - - void EmitSaveAbsolute32(uint32 offset, uint32 value); - void EmitSaveAbsoluteReg32(uint32 offset, FxScriptRegister reg); - - void EmitJumpRelative(uint16 offset); - void EmitJumpAbsolute(uint32 position); - void EmitJumpAbsoluteReg32(FxScriptRegister reg); - void EmitJumpCallAbsolute(uint32 position); - void EmitJumpReturnToCaller(); - void EmitJumpCallExternal(FxHash hashed_name); - - void EmitMoveInt32(FxScriptRegister reg, uint32 value); - - void EmitParamsStart(); - void EmitType(FxScriptValue::ValueType type); - - uint32 EmitDataString(char* str, uint16 length); - - FxScriptRegister EmitBinop(FxAstBinop* binop, FxScriptBytecodeVarHandle* handle); - - FxScriptRegister EmitRhs(FxAstNode* rhs, RhsMode mode, FxScriptBytecodeVarHandle* handle); - - FxScriptRegister EmitLiteralInt(FxAstLiteral* literal, RhsMode mode, FxScriptBytecodeVarHandle* handle); - FxScriptRegister EmitLiteralString(FxAstLiteral* literal, RhsMode mode, FxScriptBytecodeVarHandle* handle); - - - void WriteOp(uint8 base_op, uint8 spec_op); - void Write16(uint16 value); - void Write32(uint32 value); - - FxScriptRegister FindFreeRegister(); - - FxScriptBytecodeVarHandle* FindVarHandle(FxHash hashed_name); - FxScriptBytecodeActionHandle* FindActionHandle(FxHash hashed_name); - - void PrintBytecode(); - - void MarkRegisterUsed(FxScriptRegister reg); - void MarkRegisterFree(FxScriptRegister reg); - -public: - FxMPPagedArray VarHandles; - std::vector ActionHandles; - -private: - FxScriptRegisterFlag mRegsInUse = FX_REGFLAG_NONE; - - int64 mStackOffset = 0; - uint32 mStackSize = 0; - - uint16 mScopeIndex = 0; -}; - -class FxScriptBCPrinter -{ -public: - FxScriptBCPrinter(FxMPPagedArray& bytecode) - { - mBytecode = bytecode; - mBytecode.DoNotDestroy = true; - } - - void Print(); - void PrintOp(); - - -private: - uint16 Read16(); - uint32 Read32(); - - void DoPush(char* s, uint8 op_base, uint8 op_spec); - void DoPop(char* s, uint8 op_base, uint8 op_spec); - void DoLoad(char* s, uint8 op_base, uint8 op_spec); - void DoArith(char* s, uint8 op_base, uint8 op_spec); - void DoSave(char* s, uint8 op_base, uint8 op_spec); - void DoJump(char* s, uint8 op_base, uint8 op_spec); - void DoData(char* s, uint8 op_base, uint8 op_spec); - void DoType(char* s, uint8 op_base, uint8 op_spec); - void DoMove(char* s, uint8 op_base, uint8 op_spec); - -private: - uint32 mBytecodeIndex = 0; - FxMPPagedArray mBytecode; -}; - - -/////////////////////////////////////////// -// Bytecode VM -/////////////////////////////////////////// - -struct FxScriptVMCallFrame -{ - uint32 StartStackIndex = 0; -}; - -class FxScriptVM -{ -public: - FxScriptVM() = default; - - void Start(FxMPPagedArray&& bytecode) - { - mBytecode = std::move(bytecode); - mPushedTypes.Create(64); - - Stack = FX_SCRIPT_ALLOC_MEMORY(uint8, 1024); - // mStackOffset = 0; - Registers[FX_REG_SP] = 0; - memset(Registers, 0, sizeof(Registers)); - - while (mPC < mBytecode.Size()) { - ExecuteOp(); - } - - PrintRegisters(); - } - - void PrintRegisters(); - - void Push16(uint16 value); - void Push32(uint32 value); - - uint32 Pop32(); - -private: - void ExecuteOp(); - - void DoPush(uint8 op_base, uint8 op_spec); - void DoPop(uint8 op_base, uint8 op_spec); - void DoLoad(uint8 op_base, uint8 op_spec); - void DoArith(uint8 op_base, uint8 op_spec); - void DoSave(uint8 op_base, uint8 op_spec); - void DoJump(uint8 op_base, uint8 op_spec); - void DoData(uint8 op_base, uint8 op_spec); - void DoType(uint8 op_base, uint8 op_spec); - void DoMove(uint8 op_base, uint8 op_spec); - - uint16 Read16(); - uint32 Read32(); - - FxScriptVMCallFrame& PushCallFrame(); - FxScriptVMCallFrame* GetCurrentCallFrame(); - void PopCallFrame(); - - FxScriptExternalFunc* FindExternalAction(FxHash hashed_name); - -public: - // NONE, X0, X1, X2, X3, RA, XR, SP - int32 Registers[FX_REG_SIZE]; - - uint8* Stack = nullptr; - - std::vector mExternalFuncs; - - FxMPPagedArray mBytecode; - -private: - uint32 mPC = 0; - - - bool mIsInCallFrame = false; - - FxScriptVMCallFrame mCallFrames[8]; - int mCallFrameIndex = 0; - - bool mIsInParams = false; - FxMPPagedArray mPushedTypes; - - FxScriptValue::ValueType mCurrentType = FxScriptValue::NONETYPE; -}; - -//////////////////////////////////////////////// -// Script Interpreter -//////////////////////////////////////////////// -#if 0 -class FxScriptInterpreter -{ -public: - FxScriptInterpreter() = default; - - void PushScope(); - void PopScope(); - - FxScriptVar* FindVar(FxHash hashed_name); - FxScriptAction* FindAction(FxHash hashed_name); - FxScriptExternalFunc* FindExternalAction(FxHash hashed_name); - - /** - * @brief Evaluates and gets the immediate value if `value` is a reference, or returns the value if it is already immediate. - * @param value The value to query from - * @return the immediate(literal) value - */ - const FxScriptValue& GetImmediateValue(const FxScriptValue& value); - - void DefineExternalVar(const char* type, const char* name, const FxScriptValue& value); - -private: - friend class FxConfigScript; - void Create(FxAstBlock* root_block); - - void Visit(FxAstNode* node); - - void Interpret(); - - FxScriptValue VisitExternalCall(FxAstActionCall* call, FxScriptExternalFunc& func); - FxScriptValue VisitActionCall(FxAstActionCall* call); - void VisitAssignment(FxAstAssign* assign); - FxScriptValue VisitRhs(FxAstNode* node); - - bool CheckExternalCallArgs(FxAstActionCall* call, FxScriptExternalFunc& func); - - - -private: - FxAstNode* mRootBlock = nullptr; - - bool mInCommandMode = false; - - std::vector mExternalFuncs; - - FxMPPagedArray mScopes; - FxScriptScope* mCurrentScope = nullptr; -}; - -#endif -///////////////////////////////////// -// Bytecode to x86 Transpiler -///////////////////////////////////// - - -class FxScriptTranspilerX86 -{ -public: - FxScriptTranspilerX86(FxMPPagedArray& bytecode) - { - mBytecode = bytecode; - mBytecode.DoNotDestroy = true; - } - - void Print(); - void PrintOp(); - - -private: - uint16 Read16(); - uint32 Read32(); - - void DoPush(char* s, uint8 op_base, uint8 op_spec); - void DoPop(char* s, uint8 op_base, uint8 op_spec); - void DoLoad(char* s, uint8 op_base, uint8 op_spec); - void DoArith(char* s, uint8 op_base, uint8 op_spec); - void DoSave(char* s, uint8 op_base, uint8 op_spec); - void DoJump(char* s, uint8 op_base, uint8 op_spec); - void DoData(char* s, uint8 op_base, uint8 op_spec); - void DoType(char* s, uint8 op_base, uint8 op_spec); - void DoMove(char* s, uint8 op_base, uint8 op_spec); - - - void StrOut(const char* fmt, ...); - -private: - uint32 mBytecodeIndex = 0; - - uint32 mSizePushedInAction = 0; - bool mIsInAction = false; - - int mTextIndent = 0; - - FxMPPagedArray mBytecode; -}; - - -//////////////////////////////////////////// -// IR Emitter -//////////////////////////////////////////// - - -class FxScriptIREmitter -{ -public: - FxScriptIREmitter() = default; - - void BeginEmitting(FxAstNode* node); - void Emit(FxAstNode* node); - - enum RhsMode - { - RHS_FETCH_TO_REGISTER, - - /** - * @brief Pushes the value to the stack, assuming that the value does not exist yet. - */ - RHS_DEFINE_IN_MEMORY, - - RHS_ASSIGN_TO_HANDLE, - }; - - static FxScriptRegister RegFlagToReg(FxScriptRegisterFlag reg_flag); - static FxScriptRegisterFlag RegToRegFlag(FxScriptRegister reg); - - static const char* GetRegisterName(FxScriptRegister reg); - - FxMPPagedArray mBytecode {}; - - enum VarDeclareMode - { - DECLARE_DEFAULT, - DECLARE_NO_EMIT, - }; - - -private: - void EmitBlock(FxAstBlock* block); - void EmitAction(FxAstActionDecl* action); - void DoActionCall(FxAstActionCall* call); - FxScriptBytecodeVarHandle* DoVarDeclare(FxAstVarDecl* decl, VarDeclareMode mode = DECLARE_DEFAULT); - void EmitAssign(FxAstAssign* assign); - FxScriptBytecodeVarHandle* DefineAndFetchParam(FxAstNode* param_decl_node); - FxScriptBytecodeVarHandle* DefineReturnVar(FxAstVarDecl* decl); - - FxScriptRegister EmitVarFetch(FxAstVarRef* ref, RhsMode mode); - - void DoLoad(uint32 stack_offset, FxScriptRegister output_reg, bool force_absolute = false); - void DoSaveInt32(uint32 stack_offset, uint32 value, bool force_absolute = false); - void DoSaveReg32(uint32 stack_offset, FxScriptRegister reg, bool force_absolute = false); - - void EmitPush32(uint32 value); - void EmitPush32r(FxScriptRegister reg); - - void EmitPop32(FxScriptRegister output_reg); - - void EmitLoad32(int offset, FxScriptRegister output_reg); - void EmitLoadAbsolute32(uint32 position, FxScriptRegister output_reg); - - void EmitSave32(int16 offset, uint32 value); - void EmitSaveReg32(int16 offset, FxScriptRegister reg); - - void EmitSaveAbsolute32(uint32 offset, uint32 value); - void EmitSaveAbsoluteReg32(uint32 offset, FxScriptRegister reg); - - void EmitJumpRelative(uint16 offset); - void EmitJumpAbsolute(uint32 position); - void EmitJumpAbsoluteReg32(FxScriptRegister reg); - void EmitJumpCallAbsolute(uint32 position); - void EmitJumpReturnToCaller(); - void EmitJumpCallExternal(FxHash hashed_name); - - void EmitMoveInt32(FxScriptRegister reg, uint32 value); - - void EmitParamsStart(); - void EmitType(FxScriptValue::ValueType type); - - uint32 EmitDataString(char* str, uint16 length); - - FxScriptRegister EmitBinop(FxAstBinop* binop, FxScriptBytecodeVarHandle* handle); - - FxScriptRegister EmitRhs(FxAstNode* rhs, RhsMode mode, FxScriptBytecodeVarHandle* handle); - - FxScriptRegister EmitLiteralInt(FxAstLiteral* literal, RhsMode mode, FxScriptBytecodeVarHandle* handle); - FxScriptRegister EmitLiteralString(FxAstLiteral* literal, RhsMode mode, FxScriptBytecodeVarHandle* handle); - - - void WriteOp(uint8 base_op, uint8 spec_op); - void Write16(uint16 value); - void Write32(uint32 value); - - FxScriptRegister FindFreeRegister(); - - FxScriptBytecodeVarHandle* FindVarHandle(FxHash hashed_name); - FxScriptBytecodeActionHandle* FindActionHandle(FxHash hashed_name); - - void PrintBytecode(); - - void MarkRegisterUsed(FxScriptRegister reg); - void MarkRegisterFree(FxScriptRegister reg); - -public: - FxMPPagedArray VarHandles; - std::vector ActionHandles; - -private: - FxScriptRegisterFlag mRegsInUse = FX_REGFLAG_NONE; - - int64 mStackOffset = 0; - uint32 mStackSize = 0; - - uint16 mScopeIndex = 0; -}; - - -class FxScriptIRPrinter -{ -public: - FxScriptIRPrinter(FxMPPagedArray& bytecode) - { - mBytecode = bytecode; - mBytecode.DoNotDestroy = true; - } - - void Print(); - void PrintOp(); - - -private: - uint16 Read16(); - uint32 Read32(); - - void DoPush(char* s, uint8 op_base, uint8 op_spec); - void DoPop(char* s, uint8 op_base, uint8 op_spec); - void DoLoad(char* s, uint8 op_base, uint8 op_spec); - void DoArith(char* s, uint8 op_base, uint8 op_spec); - void DoSave(char* s, uint8 op_base, uint8 op_spec); - void DoJump(char* s, uint8 op_base, uint8 op_spec); - void DoData(char* s, uint8 op_base, uint8 op_spec); - void DoType(char* s, uint8 op_base, uint8 op_spec); - void DoMove(char* s, uint8 op_base, uint8 op_spec); - -private: - uint32 mBytecodeIndex = 0; - FxMPPagedArray mBytecode; -}; diff --git a/Main.cpp b/Main.cpp index 4254ed9..dad66fe 100644 --- a/Main.cpp +++ b/Main.cpp @@ -1,4 +1,4 @@ -#include "FxScript.hpp" +#include "FoxScript.hpp" #include @@ -7,12 +7,12 @@ int main() { - FxConfigScript script; - script.LoadFile("Main.fxS"); + FoxConfigScript script; + script.LoadFile("Main.fox"); - script.DefineExternalVar("playerid", "emd22", FxScriptValue(FxScriptValue::INT, 1020)); + script.DefineExternalVar("playerid", "emd22", FoxValue(FoxValue::INT, 1020)); - FxScriptVM vm; + FoxVM vm; script.Execute(vm); diff --git a/Main.fxS b/Main.fox similarity index 98% rename from Main.fxS rename to Main.fox index 245ace3..f82c730 100644 --- a/Main.fxS +++ b/Main.fox @@ -5,11 +5,6 @@ local int y = 2 + x; - - - - - // push32 5 # Offset: 0 // move32 X0, 2 # Offset: 6 // load32 -4, X1 # Offset: 12 diff --git a/Makefile b/Makefile index 84507c8..0e7038d 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ LINKFLAGS := -lc++ BUILD_DIR := build -SRC := FxScript.cpp Main.cpp +SRC := FoxScript.cpp Main.cpp OBJ := $(SRC:%.cpp=$(BUILD_DIR)/%.o) DEP := $(OBJ:.o=.d) # dependency files TARGET := fxscript From 4486a19b1ac5a81a73e9c3093fbc912bb4039168 Mon Sep 17 00:00:00 2001 From: Ethan MacDonald Date: Thu, 11 Sep 2025 11:28:22 -0300 Subject: [PATCH 3/9] Added FoxIRToArm64 with minimal instructions --- FoxScript.cpp | 384 ++++++++++++++++++++++++++++++++++++++++++++------ FoxScript.hpp | 48 +++++++ Main.fox | 12 +- 3 files changed, 391 insertions(+), 53 deletions(-) diff --git a/FoxScript.cpp b/FoxScript.cpp index 0735f66..d2bdb2e 100644 --- a/FoxScript.cpp +++ b/FoxScript.cpp @@ -374,6 +374,12 @@ void FoxConfigScript::Execute(FoxVM& vm) ir_printer.Print(); + printf("\n=====\n"); + + FoxIRToArm64 ir_to_arm64(ir_emitter.mBytecode); + + ir_to_arm64.Print(); + #if 0 FoxBCEmitter emitter; @@ -2213,7 +2219,7 @@ void FoxBCPrinter::DoJump(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == OpSpecJump_Relative) { uint16 offset = Read16(); - printf("# jump relative to (%u)\n", mBytecodeIndex + offset); + printf("// jump relative to (%u)\n", mBytecodeIndex + offset); BC_PRINT_OP("jmpr %d", offset); } else if (op_spec == OpSpecJump_Absolute) { @@ -2332,7 +2338,7 @@ void FoxBCPrinter::PrintOp() printf("%-25s", s); - printf("\t# Offset: %u\n", bc_index); + printf("\t// Offset: %u\n", bc_index); } @@ -3464,13 +3470,13 @@ FoxIRRegister FoxIREmitter::EmitVarFetch(FoxAstVarRef* ref, RhsMode mode) { FoxBytecodeVarHandle* var_handle = FindVarHandle(ref->Name->GetHash()); - bool force_absolute_load = false; + // bool force_absolute_load = false; // If the variable is from a previous scope, load it from an absolute address. local offsets // will change depending on where they are called. - if (var_handle->ScopeIndex < mScopeIndex) { - force_absolute_load = true; - } + // if (var_handle->ScopeIndex < mScopeIndex) { + // force_absolute_load = true; + // } if (!var_handle) { printf("Could not find var handle!"); @@ -3626,7 +3632,7 @@ FoxIRRegister FoxIREmitter::EmitLiteralInt(FoxAstLiteral* literal, RhsMode mode, } else if (mode == RhsMode::RHS_ASSIGN_TO_HANDLE) { - const bool force_absolute_save = (handle->ScopeIndex < mScopeIndex); + // const bool force_absolute_save = (handle->ScopeIndex < mScopeIndex); // DoSaveInt32(handle->Offset, literal->Value.ValueInt, force_absolute_save); EmitVariableSetInt32(handle->VarIndexInScope, literal->Value.ValueInt); @@ -3760,7 +3766,7 @@ FoxIRRegister FoxIREmitter::EmitRhs(FoxAstNode* rhs, FoxIREmitter::RhsMode mode, return output_reg; } else if (mode == IRRhsMode::RHS_ASSIGN_TO_HANDLE) { - const bool force_absolute_save = (handle->ScopeIndex < mScopeIndex); + // const bool force_absolute_save = (handle->ScopeIndex < mScopeIndex); // Save the value back to the variable // DoSaveReg32(handle->Offset, result_register, force_absolute_save); @@ -3781,24 +3787,24 @@ FoxBytecodeVarHandle* FoxIREmitter::DoVarDeclare(FoxAstVarDecl* decl, VarDeclare // const uint16 size_of_type = static_cast(sizeof(int32)); - const FoxHash type_int = FoxHashStr("int"); - const FoxHash type_string = FoxHashStr("string"); + // const FoxHash type_int = FoxHashStr("int"); + // const FoxHash type_string = FoxHashStr("string"); FoxHash decl_hash = decl->Name->GetHash(); - FoxHash type_hash = decl->Type->GetHash(); + // FoxHash type_hash = decl->Type->GetHash(); - FoxValue::ValueType value_type = FoxValue::INT; + // FoxValue::ValueType value_type = FoxValue::INT; - switch (type_hash) { - case type_int: - value_type = FoxValue::INT; - break; - case type_string: - value_type = FoxValue::STRING; - break; - }; + // switch (type_hash) { + // case type_int: + // value_type = FoxValue::INT; + // break; + // case type_string: + // value_type = FoxValue::STRING; + // break; + // }; - const uint16 size_of_type = GetSizeOfType(decl->Type); + // const uint16 size_of_type = GetSizeOfType(decl->Type); // FoxBytecodeVarHandle handle { // .HashedName = decl_hash, @@ -4024,9 +4030,6 @@ void FoxIREmitter::EmitBlock(FoxAstBlock* block) { RETURN_IF_NO_NODE(block); - EmitMarker(IrSpecMarker_FrameBegin); - - // For each var declared in the block, write a stack allocation in the frame header for (FoxAstNode* node : block->Statements) { if (node->NodeType == FX_AST_VARDECL) { @@ -4051,6 +4054,10 @@ void FoxIREmitter::EmitBlock(FoxAstBlock* block) } } + // After the stack allocations, mark the start of the frame. + EmitMarker(IrSpecMarker_FrameBegin); + + for (FoxAstNode* node : block->Statements) { Emit(node); } @@ -4113,11 +4120,11 @@ void FoxIRPrinter::DoLoad(char* s, uint8 op_base, uint8 op_spec_raw) if (op_spec == IrSpecLoad_Int32) { int16 offset = Read16(); - BC_PRINT_OP("load32 %d, %s", offset, FoxIREmitter::GetRegisterName(static_cast(op_reg))); + BC_PRINT_OP("load [i32] %d, %s", offset, FoxIREmitter::GetRegisterName(static_cast(op_reg))); } else if (op_spec == IrSpecLoad_AbsoluteInt32) { uint32 offset = Read32(); - BC_PRINT_OP("load32a %u, %s", offset, FoxIREmitter::GetRegisterName(static_cast(op_reg))); + BC_PRINT_OP("loada [i32] %u, %s", offset, FoxIREmitter::GetRegisterName(static_cast(op_reg))); } } @@ -4125,11 +4132,11 @@ void FoxIRPrinter::DoPush(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == IrSpecPush_Int32) { uint32 value = Read32(); - BC_PRINT_OP("push32 %u", value); + BC_PRINT_OP("push [i32] %u", value); } else if (op_spec == IrSpecPush_Reg32) { uint16 reg = Read16(); - BC_PRINT_OP("push32r %s", FoxIREmitter::GetRegisterName(static_cast(reg))); + BC_PRINT_OP("push [r32] %s", FoxIREmitter::GetRegisterName(static_cast(reg))); } else if (op_spec == IrSpecPush_StackAlloc) { uint16 size = Read16(); @@ -4143,7 +4150,7 @@ void FoxIRPrinter::DoPop(char* s, uint8 op_base, uint8 op_spec_raw) uint8 op_reg = (op_spec_raw & 0x0F); if (op_spec == IrSpecPop_Int32) { - BC_PRINT_OP("pop32 %s", FoxIREmitter::GetRegisterName(static_cast(op_reg))); + BC_PRINT_OP("pop [i32] %s", FoxIREmitter::GetRegisterName(static_cast(op_reg))); } } @@ -4153,7 +4160,7 @@ void FoxIRPrinter::DoArith(char* s, uint8 op_base, uint8 op_spec) uint8 b_reg = mBytecode[mBytecodeIndex++]; if (op_spec == IrSpecArith_Add) { - BC_PRINT_OP("add32 %s, %s", FoxIREmitter::GetRegisterName(static_cast(a_reg)), + BC_PRINT_OP("add [i32] %s, %s", FoxIREmitter::GetRegisterName(static_cast(a_reg)), FoxIREmitter::GetRegisterName(static_cast(b_reg))); } } @@ -4165,7 +4172,7 @@ void FoxIRPrinter::DoSave(char* s, uint8 op_base, uint8 op_spec) const int16 offset = Read16(); const uint32 value = Read32(); - BC_PRINT_OP("save32 %d, %u", offset, value); + BC_PRINT_OP("save [i32] %d, %u", offset, value); } // Save a register into an offset in the stack @@ -4173,19 +4180,19 @@ void FoxIRPrinter::DoSave(char* s, uint8 op_base, uint8 op_spec) const int16 offset = Read16(); uint16 reg = Read16(); - BC_PRINT_OP("save32r %d, %s", offset, FoxIREmitter::GetRegisterName(static_cast(reg))); + BC_PRINT_OP("save [r32] %d, %s", offset, FoxIREmitter::GetRegisterName(static_cast(reg))); } else if (op_spec == IrSpecSave_AbsoluteInt32) { const uint32 offset = Read32(); const uint32 value = Read32(); - BC_PRINT_OP("save32a %u, %u", offset, value); + BC_PRINT_OP("savea [i32] %u, %u", offset, value); } else if (op_spec == IrSpecSave_AbsoluteReg32) { const uint32 offset = Read32(); uint16 reg = Read16(); - BC_PRINT_OP("save32ar %u, %s", offset, FoxIREmitter::GetRegisterName(static_cast(reg))); + BC_PRINT_OP("savea [r32] %u, %s", offset, FoxIREmitter::GetRegisterName(static_cast(reg))); } } @@ -4193,7 +4200,7 @@ void FoxIRPrinter::DoJump(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == IrSpecJump_Relative) { uint16 offset = Read16(); - printf("# jump relative to (%u)\n", mBytecodeIndex + offset); + printf("// jump relative to (%u)\n", mBytecodeIndex + offset); BC_PRINT_OP("jmpr %d", offset); } else if (op_spec == IrSpecJump_Absolute) { @@ -4241,10 +4248,10 @@ void FoxIRPrinter::DoData(char* s, uint8 op_base, uint8 op_spec) void FoxIRPrinter::DoType(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == IrSpecType_Int) { - BC_PRINT_OP("typeint"); + BC_PRINT_OP("type int"); } else if (op_spec == IrSpecType_String) { - BC_PRINT_OP("typestr"); + BC_PRINT_OP("type str"); } } @@ -4255,7 +4262,7 @@ void FoxIRPrinter::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) if (op_spec == IrSpecMove_Int32) { uint32 value = Read32(); - BC_PRINT_OP("move32 %s, %u\t", FoxIREmitter::GetRegisterName(static_cast(op_reg)), value); + BC_PRINT_OP("move [i32] %s, %u\t", FoxIREmitter::GetRegisterName(static_cast(op_reg)), value); } } @@ -4278,17 +4285,17 @@ void FoxIRPrinter::DoVariable(char* s, uint8 op_base, uint8 op_spec) if (op_spec == IrSpecVariable_Get_Int32) { uint16 var_index = Read16(); FoxIRRegister dest_reg = static_cast(Read16()); - BC_PRINT_OP("vget $%d, %s", var_index, FoxIREmitter::GetRegisterName(dest_reg)); + BC_PRINT_OP("vget [i32] $%d, %s", var_index, FoxIREmitter::GetRegisterName(dest_reg)); } else if (op_spec == IrSpecVariable_Set_Int32) { uint16 var_index = Read16(); uint32 value = Read32(); - BC_PRINT_OP("vset $%d, %d", var_index, value); + BC_PRINT_OP("vset [i32] $%d, %d", var_index, value); } else if (op_spec == IrSpecVariable_Set_Reg32) { uint16 var_index = Read16(); FoxIRRegister reg = static_cast(Read16()); - BC_PRINT_OP("vset $%d, %s", var_index, FoxIREmitter::GetRegisterName(reg)); + BC_PRINT_OP("vset [r32] $%d, %s", var_index, FoxIREmitter::GetRegisterName(reg)); } } @@ -4349,5 +4356,298 @@ void FoxIRPrinter::PrintOp() printf("%-25s", s); - printf("\t# Offset: %u\n", bc_index); + printf("\t// Offset: %u\n", bc_index); +} + + +///////////////////////////////////// +// FxIRToArm64 +///////////////////////////////////// + +uint16 FoxIRToArm64::Read16() +{ + uint8 lo = mBytecode[mBytecodeIndex++]; + uint8 hi = mBytecode[mBytecodeIndex++]; + + return ((static_cast(lo) << 8) | hi); +} + +uint32 FoxIRToArm64::Read32() +{ + uint16 lo = Read16(); + uint16 hi = Read16(); + + return ((static_cast(lo) << 16) | hi); +} + +#define BC_PRINT_OP(fmt_, ...) snprintf(s, 128, fmt_, ##__VA_ARGS__) + +void FoxIRToArm64::DoLoad(char* s, uint8 op_base, uint8 op_spec_raw) +{ + uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); + uint8 op_reg = (op_spec_raw & 0x0F); + + if (op_spec == IrSpecLoad_Int32) { + int16 offset = Read16(); + BC_PRINT_OP("load [i32] %d, %s", offset, FoxIREmitter::GetRegisterName(static_cast(op_reg))); + } + else if (op_spec == IrSpecLoad_AbsoluteInt32) { + uint32 offset = Read32(); + BC_PRINT_OP("loada [i32] %u, %s", offset, FoxIREmitter::GetRegisterName(static_cast(op_reg))); + } +} + +void FoxIRToArm64::DoPush(char* s, uint8 op_base, uint8 op_spec) +{ + if (op_spec == IrSpecPush_Int32) { + uint32 value = Read32(); + BC_PRINT_OP("push [i32] %u", value); + } + else if (op_spec == IrSpecPush_Reg32) { + uint16 reg = Read16(); + BC_PRINT_OP("push [r32] %s", FoxIREmitter::GetRegisterName(static_cast(reg))); + } + else if (op_spec == IrSpecPush_StackAlloc) { + uint16 size = Read16(); + + CurrentFrame.StackAllocated += size; + + BC_PRINT_OP("salloc %d", size); + } +} + +void FoxIRToArm64::DoPop(char* s, uint8 op_base, uint8 op_spec_raw) +{ + uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); + uint8 op_reg = (op_spec_raw & 0x0F); + + if (op_spec == IrSpecPop_Int32) { + BC_PRINT_OP("pop [i32] %s", FoxIREmitter::GetRegisterName(static_cast(op_reg))); + } +} + +void FoxIRToArm64::DoArith(char* s, uint8 op_base, uint8 op_spec) +{ + uint8 a_reg = mBytecode[mBytecodeIndex++]; + uint8 b_reg = mBytecode[mBytecodeIndex++]; + + if (op_spec == IrSpecArith_Add) { + BC_PRINT_OP("add [i32] %s, %s", FoxIREmitter::GetRegisterName(static_cast(a_reg)), + FoxIREmitter::GetRegisterName(static_cast(b_reg))); + } +} + +void FoxIRToArm64::DoSave(char* s, uint8 op_base, uint8 op_spec) +{ + // Save a imm32 into an offset in the stack + if (op_spec == IrSpecSave_Int32) { + const int16 offset = Read16(); + const uint32 value = Read32(); + + BC_PRINT_OP("save [i32] %d, %u", offset, value); + } + + // Save a register into an offset in the stack + else if (op_spec == IrSpecSave_Reg32) { + const int16 offset = Read16(); + uint16 reg = Read16(); + + BC_PRINT_OP("save [r32] %d, %s", offset, FoxIREmitter::GetRegisterName(static_cast(reg))); + } + else if (op_spec == IrSpecSave_AbsoluteInt32) { + const uint32 offset = Read32(); + const uint32 value = Read32(); + + BC_PRINT_OP("savea [i32] %u, %u", offset, value); + } + else if (op_spec == IrSpecSave_AbsoluteReg32) { + const uint32 offset = Read32(); + uint16 reg = Read16(); + + BC_PRINT_OP("savea [r32] %u, %s", offset, FoxIREmitter::GetRegisterName(static_cast(reg))); + } +} + +void FoxIRToArm64::DoJump(char* s, uint8 op_base, uint8 op_spec) +{ + if (op_spec == IrSpecJump_Relative) { + uint16 offset = Read16(); + printf("// jump relative to (%u)\n", mBytecodeIndex + offset); + BC_PRINT_OP("jmpr %d", offset); + } + else if (op_spec == IrSpecJump_Absolute) { + uint32 position = Read32(); + BC_PRINT_OP("jmpa %u", position); + } + else if (op_spec == IrSpecJump_AbsoluteReg32) { + uint16 reg = Read16(); + BC_PRINT_OP("jmpar %s", FoxIREmitter::GetRegisterName(static_cast(reg))); + } + else if (op_spec == IrSpecJump_CallAbsolute) { + uint32 position = Read32(); + BC_PRINT_OP("calla %u", position); + } + else if (op_spec == IrSpecJump_ReturnToCaller) { + BC_PRINT_OP("ret"); + } + else if (op_spec == IrSpecJump_CallExternal) { + uint32 hashed_name = Read32(); + BC_PRINT_OP("callext %u", hashed_name); + } +} + + +void FoxIRToArm64::DoData(char* s, uint8 op_base, uint8 op_spec) +{ + if (op_spec == IrSpecData_String) { + uint16 length = Read16(); + char* data_str = FX_SCRIPT_ALLOC_MEMORY(char, length); + uint16* data_str16 = reinterpret_cast(data_str); + + uint32 bytecode_end = mBytecodeIndex + length; + int data_index = 0; + while (mBytecodeIndex < bytecode_end) { + uint16 value16 = Read16(); + data_str16[data_index++] = ((value16 << 8) | (value16 >> 8)); + } + + BC_PRINT_OP("datastr %d, %.*s", length, length, data_str); + + FX_SCRIPT_FREE(char, data_str); + } +} + +void FoxIRToArm64::DoType(char* s, uint8 op_base, uint8 op_spec) +{ + if (op_spec == IrSpecType_Int) { + BC_PRINT_OP("type int"); + } + else if (op_spec == IrSpecType_String) { + BC_PRINT_OP("type str"); + } +} + +void FoxIRToArm64::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) +{ + uint8 op_spec = ((op_spec_raw >> 4) & 0x0F); + uint8 op_reg = (op_spec_raw & 0x0F); + + if (op_spec == IrSpecMove_Int32) { + uint32 value = Read32(); + BC_PRINT_OP("move [i32] %s, %u\t", FoxIREmitter::GetRegisterName(static_cast(op_reg)), value); + } +} + +void FoxIRToArm64::DoMarker(char* s, uint8 op_base, uint8 op_spec) +{ + if (op_spec == IrSpecMarker_FrameBegin) { + CurrentFrame.StackAllocated = MakeValueFactorOf16(CurrentFrame.StackAllocated); + BC_PRINT_OP("sub sp, sp, #%u", CurrentFrame.StackAllocated); + } + else if (op_spec == IrSpecMarker_FrameEnd) { + BC_PRINT_OP("add sp, sp, #%u", CurrentFrame.StackAllocated); + // Reset the current stack frame + ResetFrame(); + } + else if (op_spec == IrSpecMarker_ParamsBegin) { + BC_PRINT_OP("params begin"); + } +} + + +void FoxIRToArm64::DoVariable(char* s, uint8 op_base, uint8 op_spec) +{ + if (op_spec == IrSpecVariable_Get_Int32) { + uint16 var_index = Read16(); + FoxIRRegister dest_reg = static_cast(Read16()); + BC_PRINT_OP("vget [i32] $%d, %s", var_index, FoxIREmitter::GetRegisterName(dest_reg)); + } + else if (op_spec == IrSpecVariable_Set_Int32) { + uint16 var_index = Read16(); + uint32 value = Read32(); + BC_PRINT_OP("vset [i32] $%d, %d", var_index, value); + } + else if (op_spec == IrSpecVariable_Set_Reg32) { + uint16 var_index = Read16(); + FoxIRRegister reg = static_cast(Read16()); + BC_PRINT_OP("vset [r32] $%d, %s", var_index, FoxIREmitter::GetRegisterName(reg)); + } +} + + +void FoxIRToArm64::Print() +{ + while (mBytecodeIndex < mBytecode.Size()) { + PrintOp(); + } +} + +void FoxIRToArm64::PrintOp() +{ + uint32 bc_index = mBytecodeIndex; + + uint16 op_full = Read16(); + + const uint8 op_base = static_cast(op_full >> 8); + const uint8 op_spec = static_cast(op_full & 0xFF); + + char s[128]; + + switch (op_base) { + case IrBase_Push: + DoPush(s, op_base, op_spec); + break; + case IrBase_Pop: + DoPop(s, op_base, op_spec); + break; + case IrBase_Load: + DoLoad(s, op_base, op_spec); + break; + case IrBase_Arith: + DoArith(s, op_base, op_spec); + break; + case IrBase_Jump: + DoJump(s, op_base, op_spec); + break; + case IrBase_Save: + DoSave(s, op_base, op_spec); + break; + case IrBase_Data: + DoData(s, op_base, op_spec); + break; + case IrBase_Type: + DoType(s, op_base, op_spec); + break; + case IrBase_Move: + DoMove(s, op_base, op_spec); + break; + case IrBase_Marker: + DoMarker(s, op_base, op_spec); + break; + case IrBase_Variable: + DoVariable(s, op_base, op_spec); + break; + } + + printf("%-25s", s); + + printf("\t// Offset: %u\n", bc_index); +} + +uint32 FoxIRToArm64::MakeValueFactorOf16(uint32 value) +{ + // Get the bottom four bits (value % 16) + const uint8 remainder = (value & 0x0F); + + if (remainder != 0) { + value += (16 - remainder); + } + + return value; +} + + +void FoxIRToArm64::ResetFrame() +{ + std::memset(&CurrentFrame, 0, sizeof(CurrentFrame)); } diff --git a/FoxScript.hpp b/FoxScript.hpp index d8c9bda..0c8e617 100644 --- a/FoxScript.hpp +++ b/FoxScript.hpp @@ -1210,3 +1210,51 @@ class FoxIRPrinter uint32 mBytecodeIndex = 0; FoxMPPagedArray mBytecode; }; + + +struct FoxIRArm64Frame +{ + uint32 StackAllocated = 0; +}; + + +class FoxIRToArm64 +{ +public: + FoxIRToArm64(FoxMPPagedArray& bytecode) + { + mBytecode = bytecode; + mBytecode.DoNotDestroy = true; + } + + void Print(); + void PrintOp(); + + +private: + uint16 Read16(); + uint32 Read32(); + + void DoPush(char* s, uint8 op_base, uint8 op_spec); + void DoPop(char* s, uint8 op_base, uint8 op_spec); + void DoLoad(char* s, uint8 op_base, uint8 op_spec); + void DoArith(char* s, uint8 op_base, uint8 op_spec); + void DoSave(char* s, uint8 op_base, uint8 op_spec); + void DoJump(char* s, uint8 op_base, uint8 op_spec); + void DoData(char* s, uint8 op_base, uint8 op_spec); + void DoType(char* s, uint8 op_base, uint8 op_spec); + void DoMove(char* s, uint8 op_base, uint8 op_spec); + void DoMarker(char* s, uint8 op_base, uint8 op_spec); + void DoVariable(char* s, uint8 op_base, uint8 op_spec); + +private: + void ResetFrame(); + + uint32 MakeValueFactorOf16(uint32 value); + +private: + uint32 mBytecodeIndex = 0; + FoxMPPagedArray mBytecode; + + FoxIRArm64Frame CurrentFrame; +}; diff --git a/Main.fox b/Main.fox index f82c730..ccb69e7 100644 --- a/Main.fox +++ b/Main.fox @@ -1,12 +1,2 @@ - local int x = 5; -local int y = 2 + x; - - - - -// push32 5 # Offset: 0 -// move32 X0, 2 # Offset: 6 -// load32 -4, X1 # Offset: 12 -// add32 X0, X1 # Offset: 16 -// push32r XR # Offset: 20 +local int y = x + 2; \ No newline at end of file From 36d3acfc125d67d2618c214f8e0a373a781f552e Mon Sep 17 00:00:00 2001 From: Ethan MacDonald Date: Thu, 11 Sep 2025 12:29:51 -0300 Subject: [PATCH 4/9] Added more instructions to arm64 backend, compiles minimal file now --- FoxScript.cpp | 154 ++++++++++++++++++++++++++++++++++++++---- FoxScript.hpp | 39 +++++++++++ FoxScriptBytecode.hpp | 2 +- 3 files changed, 180 insertions(+), 15 deletions(-) diff --git a/FoxScript.cpp b/FoxScript.cpp index d2bdb2e..2cf36c9 100644 --- a/FoxScript.cpp +++ b/FoxScript.cpp @@ -3453,7 +3453,7 @@ FoxIRRegister FoxIREmitter::EmitBinop(FoxAstBinop* binop, FoxBytecodeVarHandle* } if (binop->OpToken->Type == TT::Plus) { - WriteOp(IrBase_Arith, IrSpecArith_Add); + WriteOp(IrBase_Arith, IrSpecArith_Add_Reg32); mBytecode.Insert(a_reg); mBytecode.Insert(b_reg); @@ -4159,7 +4159,7 @@ void FoxIRPrinter::DoArith(char* s, uint8 op_base, uint8 op_spec) uint8 a_reg = mBytecode[mBytecodeIndex++]; uint8 b_reg = mBytecode[mBytecodeIndex++]; - if (op_spec == IrSpecArith_Add) { + if (op_spec == IrSpecArith_Add_Reg32) { BC_PRINT_OP("add [i32] %s, %s", FoxIREmitter::GetRegisterName(static_cast(a_reg)), FoxIREmitter::GetRegisterName(static_cast(b_reg))); } @@ -4412,7 +4412,7 @@ void FoxIRToArm64::DoPush(char* s, uint8 op_base, uint8 op_spec) CurrentFrame.StackAllocated += size; - BC_PRINT_OP("salloc %d", size); + BC_PRINT_OP("// salloc %d", size); } } @@ -4428,12 +4428,17 @@ void FoxIRToArm64::DoPop(char* s, uint8 op_base, uint8 op_spec_raw) void FoxIRToArm64::DoArith(char* s, uint8 op_base, uint8 op_spec) { - uint8 a_reg = mBytecode[mBytecodeIndex++]; - uint8 b_reg = mBytecode[mBytecodeIndex++]; + FoxIRRegister a_reg = static_cast(mBytecode[mBytecodeIndex++]); + FoxIRRegister b_reg = static_cast(mBytecode[mBytecodeIndex++]); - if (op_spec == IrSpecArith_Add) { - BC_PRINT_OP("add [i32] %s, %s", FoxIREmitter::GetRegisterName(static_cast(a_reg)), - FoxIREmitter::GetRegisterName(static_cast(b_reg))); + if (op_spec == IrSpecArith_Add_Reg32) { + // BC_PRINT_OP("add [i32] %s, %s", FoxIREmitter::GetRegisterName(static_cast(a_reg)), + // FoxIREmitter::GetRegisterName(static_cast(b_reg))); + + const char* lhs_reg = GetRegisterName(GetGeneralRegFromIR(a_reg)); + const char* rhs_reg = GetRegisterName(GetGeneralRegFromIR(b_reg)); + + BC_PRINT_OP("add %s, %s, %s", lhs_reg, lhs_reg, rhs_reg); } } @@ -4533,8 +4538,12 @@ void FoxIRToArm64::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) uint8 op_reg = (op_spec_raw & 0x0F); if (op_spec == IrSpecMove_Int32) { - uint32 value = Read32(); - BC_PRINT_OP("move [i32] %s, %u\t", FoxIREmitter::GetRegisterName(static_cast(op_reg)), value); + int value = static_cast(Read32()); + const FoxArm64Register dest_reg = GetGeneralRegFromIR(static_cast(op_reg)); + + // BC_PRINT_OP("move [i32] %s, %u\t", FoxIREmitter::GetRegisterName(), value); + + BC_PRINT_OP("mov %s, #%d", GetRegisterName(dest_reg), value); } } @@ -4559,18 +4568,40 @@ void FoxIRToArm64::DoVariable(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == IrSpecVariable_Get_Int32) { uint16 var_index = Read16(); - FoxIRRegister dest_reg = static_cast(Read16()); - BC_PRINT_OP("vget [i32] $%d, %s", var_index, FoxIREmitter::GetRegisterName(dest_reg)); + // BC_PRINT_OP("vget [i32] $%d, %s", var_index, FoxIREmitter::GetRegisterName(dest_reg)); + + const FoxIRRegister dest_ir_reg = static_cast(Read16()); + const FoxArm64Register dest_reg = GetGeneralRegFromIR(dest_ir_reg); + + const uint32 var_stack_offset = CurrentFrame.StackAllocated - ((var_index + 1) * 4); + + BC_PRINT_OP("ldr %s, [sp, #%u]", GetRegisterName(dest_reg), var_stack_offset); } else if (op_spec == IrSpecVariable_Set_Int32) { uint16 var_index = Read16(); uint32 value = Read32(); - BC_PRINT_OP("vset [i32] $%d, %d", var_index, value); + // BC_PRINT_OP("vset [i32] $%d, %d", var_index, value); + + FoxArm64Register reg = RegisterRequest(Usage_General); + + const char* reg_name = GetRegisterName(reg); + + printf("mov %s, #%d\n", reg_name, static_cast(value)); + + const uint32 var_stack_offset = CurrentFrame.StackAllocated - ((var_index + 1) * 4); + + BC_PRINT_OP("str %s, [sp, #%u]", reg_name, var_stack_offset); + + RegisterRelease(reg); } else if (op_spec == IrSpecVariable_Set_Reg32) { uint16 var_index = Read16(); FoxIRRegister reg = static_cast(Read16()); - BC_PRINT_OP("vset [r32] $%d, %s", var_index, FoxIREmitter::GetRegisterName(reg)); + + const uint32 var_stack_offset = CurrentFrame.StackAllocated - ((var_index + 1) * 4); + + BC_PRINT_OP("str %s, [sp, #%u]", GetRegisterName(GetGeneralRegFromIR(reg)), var_stack_offset); + // BC_PRINT_OP("vset [r32] $%d, %s", var_index, FoxIREmitter::GetRegisterName(reg)); } } @@ -4646,8 +4677,103 @@ uint32 FoxIRToArm64::MakeValueFactorOf16(uint32 value) return value; } +FoxArm64Register FoxIRToArm64::RegisterRequest(FoxIRToArm64::RegisterUsage usage) +{ + FoxArm64Register min, max; + + switch (usage) { + case Usage_Parameters: + min = Fox_Arm64_W0; + max = Fox_Arm64_W7; + break; + case Usage_General: + min = Fox_Arm64_W8; + max = Fox_Arm64_W15; + break; + case Usage_Return: + RegisterRelease(Fox_Arm64_W0); + + min = Fox_Arm64_W0; + max = Fox_Arm64_W0; + break; + } + + while (min <= max) { + const uint32 reg_flag = (1 << min); + + + // If register is not in use, return it + if (!(CurrentFrame.RegistersInUse & reg_flag)) { + // Mark the register as in use + CurrentFrame.RegistersInUse |= reg_flag; + + return min; + } + + // Increment the register + min = static_cast(static_cast(min) + 1); + } + + + return Fox_Arm64_None; +} + + +void FoxIRToArm64::RegisterRelease(FoxArm64Register reg) +{ + CurrentFrame.RegistersInUse &= ~(1 << reg); +} + void FoxIRToArm64::ResetFrame() { std::memset(&CurrentFrame, 0, sizeof(CurrentFrame)); } + +FoxArm64Register FoxIRToArm64::GetGeneralRegFromIR(FoxIRRegister ir_reg) +{ + return static_cast(static_cast(Fox_Arm64_W8) + static_cast(ir_reg)); +} + + +const char* FoxIRToArm64::GetRegisterName(FoxArm64Register reg) +{ + switch (reg) { + case Fox_Arm64_W0: + return "w0"; + case Fox_Arm64_W1: + return "w1"; + case Fox_Arm64_W2: + return "w2"; + case Fox_Arm64_W3: + return "w3"; + case Fox_Arm64_W4: + return "w4"; + case Fox_Arm64_W5: + return "w5"; + case Fox_Arm64_W6: + return "w6"; + case Fox_Arm64_W7: + return "w7"; + case Fox_Arm64_W8: + return "w8"; + case Fox_Arm64_W9: + return "w9"; + case Fox_Arm64_W10: + return "w10"; + case Fox_Arm64_W11: + return "w11"; + case Fox_Arm64_W12: + return "w12"; + case Fox_Arm64_W13: + return "w13"; + case Fox_Arm64_W14: + return "w14"; + case Fox_Arm64_W15: + return "w15"; + case Fox_Arm64_None: + return "(none)"; + } + + return "(unknown)"; +} diff --git a/FoxScript.hpp b/FoxScript.hpp index 0c8e617..654da6f 100644 --- a/FoxScript.hpp +++ b/FoxScript.hpp @@ -1215,11 +1215,42 @@ class FoxIRPrinter struct FoxIRArm64Frame { uint32 StackAllocated = 0; + uint32 RegistersInUse = 0; }; +enum FoxArm64Register +{ + Fox_Arm64_W0, + Fox_Arm64_W1, + Fox_Arm64_W2, + Fox_Arm64_W3, + Fox_Arm64_W4, + Fox_Arm64_W5, + Fox_Arm64_W6, + Fox_Arm64_W7, + Fox_Arm64_W8, + Fox_Arm64_W9, + Fox_Arm64_W10, + Fox_Arm64_W11, + Fox_Arm64_W12, + Fox_Arm64_W13, + Fox_Arm64_W14, + Fox_Arm64_W15, + + Fox_Arm64_None, +}; + class FoxIRToArm64 { +public: + enum RegisterUsage + { + Usage_Parameters, + Usage_General, + Usage_Return, + }; + public: FoxIRToArm64(FoxMPPagedArray& bytecode) { @@ -1252,6 +1283,14 @@ class FoxIRToArm64 uint32 MakeValueFactorOf16(uint32 value); + FoxArm64Register RegisterRequest(RegisterUsage usage); + void RegisterRelease(FoxArm64Register reg); + + FoxArm64Register GetGeneralRegFromIR(FoxIRRegister ir_reg); + + const char* GetRegisterName(FoxArm64Register reg); + + private: uint32 mBytecodeIndex = 0; FoxMPPagedArray mBytecode; diff --git a/FoxScriptBytecode.hpp b/FoxScriptBytecode.hpp index 0662e07..214d1a7 100644 --- a/FoxScriptBytecode.hpp +++ b/FoxScriptBytecode.hpp @@ -122,7 +122,7 @@ enum IrSpecLoad : uint8 enum IrSpecArith : uint8 { - IrSpecArith_Add = 1 // ADD [%r32] [%r32] + IrSpecArith_Add_Reg32 = 1 // ADD [%r32] [%r32] }; enum IrSpecSave : uint8 From 27690cb92cfbcab7de0d4edb5412fdcdce4edf9e Mon Sep 17 00:00:00 2001 From: Ethan MacDonald Date: Sat, 13 Sep 2025 19:30:37 -0300 Subject: [PATCH 5/9] Compiling changes --- FoxScript.cpp | 248 +++++++++++++++++++++++++++++++----------- FoxScript.hpp | 27 ++++- FoxScriptBytecode.hpp | 3 + Main.fox | 9 +- Test | Bin 0 -> 33480 bytes Test.asm | 53 +++++++++ Test.c | 12 ++ Test.s | 44 ++++++++ Test1 | 44 ++++++++ 9 files changed, 370 insertions(+), 70 deletions(-) create mode 100755 Test create mode 100644 Test.asm create mode 100644 Test.c create mode 100644 Test.s create mode 100644 Test1 diff --git a/FoxScript.cpp b/FoxScript.cpp index 2cf36c9..4062abd 100644 --- a/FoxScript.cpp +++ b/FoxScript.cpp @@ -188,23 +188,29 @@ FoxAstNode* FoxConfigScript::TryParseKeyword(FoxAstBlock* parent_block) if (hash == kw_return) { EatToken(TT::Identifier); + FoxAstNode* return_rhs = nullptr; + if (GetToken().Type != TT::Semicolon) { // There is a value that follows, get the value - FoxAstNode* rhs = ParseRhs(); + // FoxAstNode* rhs = ParseRhs(); + return_rhs = ParseRhs(); + // Assign the return value to __ReturnVal__ - FoxAstVarRef* var_ref = FX_SCRIPT_ALLOC_NODE(FoxAstVarRef); - var_ref->Name = mTokenReturnVar; + // FoxAstVarRef* var_ref = FX_SCRIPT_ALLOC_NODE(FoxAstVarRef); + // var_ref->Name = mTokenReturnVar; - FoxAstAssign* assign = FX_SCRIPT_ALLOC_NODE(FoxAstAssign); - assign->Var = var_ref; - assign->Rhs = rhs; + // FoxAstAssign* assign = FX_SCRIPT_ALLOC_NODE(FoxAstAssign); + // assign->Var = var_ref; + // assign->Rhs = rhs; - parent_block->Statements.push_back(assign); + // parent_block->Statements.push_back(assign); } FoxAstReturn* ret = FX_SCRIPT_ALLOC_NODE(FoxAstReturn); + ret->Rhs = return_rhs; + return ret; } if (hash == kw_help) { @@ -3100,18 +3106,55 @@ void FoxIREmitter::Emit(FoxAstNode* node) return; } else if (node->NodeType == FX_AST_RETURN) { - constexpr FoxHash return_val_hash = FoxHashStr(FX_SCRIPT_VAR_RETURN_VAL); + FoxAstReturn* return_node = reinterpret_cast(node); - FoxBytecodeVarHandle* return_var = FindVarHandle(return_val_hash); + // Is there a return value provided? + if (return_node->Rhs) { + FoxAstNode* return_rhs = return_node->Rhs; - FoxIRRegister result_register = FindFreeReg32(); - MARK_REGISTER_USED(result_register); + // Check to see if its a literal + if (return_rhs->NodeType == FX_AST_LITERAL) { + FoxAstLiteral* literal = reinterpret_cast(return_rhs); - if (return_var) { - DoLoad(return_var->Offset, result_register); + if (literal->Value.Type == FoxValue::INT) { + EmitJumpReturnToCallerInt32(literal->Value.ValueInt); + } + else if (literal->Value.Type == FoxValue::REF) { + const FoxAstVarRef* var_ref = literal->Value.ValueRef; + + // Get the variable and load it into a register. + FoxBytecodeVarHandle* var_to_return = FindVarHandle(var_ref->Name->GetHash()); + + FoxIRRegister var_to_return_reg = FindFreeReg32(); + MARK_REGISTER_USED(var_to_return_reg); + + if (var_to_return) { + DoLoad(var_to_return->Offset, var_to_return_reg); + } + + // Free the register as we will not need it after scope end + MARK_REGISTER_FREE(var_to_return_reg); + + // Return with the register + EmitJumpReturnToCallerReg32(var_to_return_reg); + } + } + + return; } - MARK_REGISTER_FREE(result_register); + // constexpr FoxHash return_val_hash = FoxHashStr(FX_SCRIPT_VAR_RETURN_VAL); + + // FoxBytecodeVarHandle* return_var = FindVarHandle(return_val_hash); + + // FoxIRRegister result_register = FindFreeReg32(); + // MARK_REGISTER_USED(result_register); + + // if (return_var) { + // DoLoad(return_var->Offset, result_register); + // } + + // MARK_REGISTER_FREE(result_register); EmitJumpReturnToCaller(); @@ -3359,6 +3402,18 @@ void FoxIREmitter::EmitJumpReturnToCaller() WriteOp(IrBase_Jump, IrSpecJump_ReturnToCaller); } +void FoxIREmitter::EmitJumpReturnToCallerReg32(FoxIRRegister reg) +{ + WriteOp(IrBase_Jump, IrSpecJump_ReturnToCaller_Reg32); + Write16(reg); +} + +void FoxIREmitter::EmitJumpReturnToCallerInt32(int32 value) +{ + WriteOp(IrBase_Jump, IrSpecJump_ReturnToCaller_Int32); + Write32(value); +} + void FoxIREmitter::EmitMoveInt32(FoxIRRegister reg, uint32 value) { WriteOp(IrBase_Move, (IrSpecMove_Int32 << 4) | (reg & 0x0F)); @@ -3787,34 +3842,34 @@ FoxBytecodeVarHandle* FoxIREmitter::DoVarDeclare(FoxAstVarDecl* decl, VarDeclare // const uint16 size_of_type = static_cast(sizeof(int32)); - // const FoxHash type_int = FoxHashStr("int"); - // const FoxHash type_string = FoxHashStr("string"); + const FoxHash type_int = FoxHashStr("int"); + const FoxHash type_string = FoxHashStr("string"); FoxHash decl_hash = decl->Name->GetHash(); - // FoxHash type_hash = decl->Type->GetHash(); + FoxHash type_hash = decl->Type->GetHash(); - // FoxValue::ValueType value_type = FoxValue::INT; + FoxValue::ValueType value_type = FoxValue::INT; - // switch (type_hash) { - // case type_int: - // value_type = FoxValue::INT; - // break; - // case type_string: - // value_type = FoxValue::STRING; - // break; - // }; + switch (type_hash) { + case type_int: + value_type = FoxValue::INT; + break; + case type_string: + value_type = FoxValue::STRING; + break; + }; - // const uint16 size_of_type = GetSizeOfType(decl->Type); + const uint16 size_of_type = GetSizeOfType(decl->Type); - // FoxBytecodeVarHandle handle { - // .HashedName = decl_hash, - // .Type = value_type, // Just int for now - // .Offset = (mStackOffset), - // .SizeOnStack = size_of_type, - // .ScopeIndex = mScopeIndex, - // }; + FoxBytecodeVarHandle handle { + .HashedName = decl_hash, + .Type = value_type, // Just int for now + .Offset = (mStackOffset), + .SizeOnStack = size_of_type, + .ScopeIndex = mScopeIndex, + }; - // VarHandles.Insert(handle); + VarHandles.Insert(handle); // FoxBytecodeVarHandle* inserted_handle = &VarHandles[VarHandles.Size() - 1]; @@ -3954,11 +4009,11 @@ void FoxIREmitter::EmitFunction(FoxAstFunctionDecl* function) printf("Start of function %zu\n", start_of_function); // Emit the jump instruction, we will update the jump position after emitting all of the code inside the block - EmitJumpRelative(0); + // EmitJumpRelative(0); // const uint32 initial_stack_offset = mStackOffset; - const size_t header_jump_start_index = start_of_function + sizeof(uint16); + // const size_t header_jump_start_index = start_of_function + sizeof(uint16); size_t start_var_handle_count = VarHandles.Size(); @@ -3971,7 +4026,7 @@ void FoxIREmitter::EmitFunction(FoxAstFunctionDecl* function) DefineAndFetchParam(param_decl_node); } - FoxBytecodeVarHandle* return_var = DefineReturnVar(function->ReturnVar); + // FoxBytecodeVarHandle* return_var = DefineReturnVar(function->ReturnVar); EmitBlock(function->Block); @@ -3989,25 +4044,25 @@ void FoxIREmitter::EmitFunction(FoxAstFunctionDecl* function) if (!block_has_return) { EmitJumpReturnToCaller(); - FoxIRRegister result_register = FindFreeReg32(); + // FoxIRRegister result_register = FindFreeReg32(); - MARK_REGISTER_USED(result_register); + // MARK_REGISTER_USED(result_register); - if (return_var != nullptr) { - DoLoad(return_var->Offset, result_register); - } + // if (return_var != nullptr) { + // DoLoad(return_var->Offset, result_register); + // } } } // Return offset back to pre-call mStackOffset -= 4; - const size_t end_of_function = mBytecode.Size(); - const uint16 distance_to_function = static_cast(end_of_function - (start_of_function)-4); + // const size_t end_of_function = mBytecode.Size(); + // const uint16 distance_to_function = static_cast(end_of_function - (start_of_function)-4); // Update the jump to the end of the function - mBytecode[header_jump_start_index] = static_cast(distance_to_function >> 8); - mBytecode[header_jump_start_index + 1] = static_cast((distance_to_function & 0xFF)); + // mBytecode[header_jump_start_index] = static_cast(distance_to_function >> 8); + // mBytecode[header_jump_start_index + 1] = static_cast((distance_to_function & 0xFF)); FoxBytecodeFunctionHandle function_handle {.HashedName = function->Name->GetHash(), .BytecodeIndex = static_cast(start_of_function + 4)}; @@ -4218,6 +4273,15 @@ void FoxIRPrinter::DoJump(char* s, uint8 op_base, uint8 op_spec) else if (op_spec == IrSpecJump_ReturnToCaller) { BC_PRINT_OP("ret"); } + else if (op_spec == IrSpecJump_ReturnToCaller_Reg32) { + const char* reg_name = FoxIREmitter::GetRegisterName(static_cast(Read16())); + + BC_PRINT_OP("ret [r32] %s", reg_name); + } + else if (op_spec == IrSpecJump_ReturnToCaller_Int32) { + int32 value = Read32(); + BC_PRINT_OP("ret [i32] %d", value); + } else if (op_spec == IrSpecJump_CallExternal) { uint32 hashed_name = Read32(); BC_PRINT_OP("callext %u", hashed_name); @@ -4410,7 +4474,7 @@ void FoxIRToArm64::DoPush(char* s, uint8 op_base, uint8 op_spec) else if (op_spec == IrSpecPush_StackAlloc) { uint16 size = Read16(); - CurrentFrame.StackAllocated += size; + PreFrameStackAllocation += size; BC_PRINT_OP("// salloc %d", size); } @@ -4492,9 +4556,21 @@ void FoxIRToArm64::DoJump(char* s, uint8 op_base, uint8 op_spec) uint32 position = Read32(); BC_PRINT_OP("calla %u", position); } + else if (op_spec == IrSpecJump_ReturnToCaller) { BC_PRINT_OP("ret"); } + else if (op_spec == IrSpecJump_ReturnToCaller_Reg32) { + const FoxArm64Register value_reg = GetGeneralRegFromIR(static_cast(Read16())); + + printf("mov w0, %s\n", GetRegisterName(value_reg)); + BC_PRINT_OP("ret"); + } + else if (op_spec == IrSpecJump_ReturnToCaller_Int32) { + printf("mov w0, #%d\n", Read32()); + BC_PRINT_OP("ret"); + } + else if (op_spec == IrSpecJump_CallExternal) { uint32 hashed_name = Read32(); BC_PRINT_OP("callext %u", hashed_name); @@ -4516,7 +4592,7 @@ void FoxIRToArm64::DoData(char* s, uint8 op_base, uint8 op_spec) data_str16[data_index++] = ((value16 << 8) | (value16 >> 8)); } - BC_PRINT_OP("datastr %d, %.*s", length, length, data_str); + BC_PRINT_OP("// datastr %d, %.*s", length, length, data_str); FX_SCRIPT_FREE(char, data_str); } @@ -4525,10 +4601,10 @@ void FoxIRToArm64::DoData(char* s, uint8 op_base, uint8 op_spec) void FoxIRToArm64::DoType(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == IrSpecType_Int) { - BC_PRINT_OP("type int"); + BC_PRINT_OP("// type int"); } else if (op_spec == IrSpecType_String) { - BC_PRINT_OP("type str"); + BC_PRINT_OP("// type str"); } } @@ -4550,16 +4626,32 @@ void FoxIRToArm64::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) void FoxIRToArm64::DoMarker(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == IrSpecMarker_FrameBegin) { - CurrentFrame.StackAllocated = MakeValueFactorOf16(CurrentFrame.StackAllocated); - BC_PRINT_OP("sub sp, sp, #%u", CurrentFrame.StackAllocated); + uint32 stack_allocation = MakeValueFactorOf16(PreFrameStackAllocation); + + // Storage for the frame pointer and link register (x29 & x30) + stack_allocation += 16; + + FoxIRArm64Frame* current_frame = FramePush(); + current_frame->StackAllocated = stack_allocation; + + printf("sub sp, sp, #%u\n", current_frame->StackAllocated); + + + // Store the frame pointer and link address to the + printf("stp x29, x30, [sp, #16]\n"); + + // Move the SP back to ignore the storage for the above + BC_PRINT_OP("add x29, sp, #16"); } else if (op_spec == IrSpecMarker_FrameEnd) { - BC_PRINT_OP("add sp, sp, #%u", CurrentFrame.StackAllocated); + BC_PRINT_OP("add sp, sp, #%u", GetCurrentFrame()->StackAllocated); + FramePop(); + + // Reset the current stack frame - ResetFrame(); } else if (op_spec == IrSpecMarker_ParamsBegin) { - BC_PRINT_OP("params begin"); + BC_PRINT_OP("// params begin"); } } @@ -4573,7 +4665,7 @@ void FoxIRToArm64::DoVariable(char* s, uint8 op_base, uint8 op_spec) const FoxIRRegister dest_ir_reg = static_cast(Read16()); const FoxArm64Register dest_reg = GetGeneralRegFromIR(dest_ir_reg); - const uint32 var_stack_offset = CurrentFrame.StackAllocated - ((var_index + 1) * 4); + const uint32 var_stack_offset = GetCurrentFrame()->StackAllocated - ((var_index + 1) * 4); BC_PRINT_OP("ldr %s, [sp, #%u]", GetRegisterName(dest_reg), var_stack_offset); } @@ -4588,7 +4680,7 @@ void FoxIRToArm64::DoVariable(char* s, uint8 op_base, uint8 op_spec) printf("mov %s, #%d\n", reg_name, static_cast(value)); - const uint32 var_stack_offset = CurrentFrame.StackAllocated - ((var_index + 1) * 4); + const uint32 var_stack_offset = GetCurrentFrame()->StackAllocated - ((var_index + 1) * 4); BC_PRINT_OP("str %s, [sp, #%u]", reg_name, var_stack_offset); @@ -4598,7 +4690,7 @@ void FoxIRToArm64::DoVariable(char* s, uint8 op_base, uint8 op_spec) uint16 var_index = Read16(); FoxIRRegister reg = static_cast(Read16()); - const uint32 var_stack_offset = CurrentFrame.StackAllocated - ((var_index + 1) * 4); + const uint32 var_stack_offset = GetCurrentFrame()->StackAllocated - ((var_index + 1) * 4); BC_PRINT_OP("str %s, [sp, #%u]", GetRegisterName(GetGeneralRegFromIR(reg)), var_stack_offset); // BC_PRINT_OP("vset [r32] $%d, %s", var_index, FoxIREmitter::GetRegisterName(reg)); @@ -4701,11 +4793,12 @@ FoxArm64Register FoxIRToArm64::RegisterRequest(FoxIRToArm64::RegisterUsage usage while (min <= max) { const uint32 reg_flag = (1 << min); + FoxIRArm64Frame* current_frame = &mStackFrames.GetLast(); // If register is not in use, return it - if (!(CurrentFrame.RegistersInUse & reg_flag)) { + if (!(current_frame->RegistersInUse & reg_flag)) { // Mark the register as in use - CurrentFrame.RegistersInUse |= reg_flag; + current_frame->RegistersInUse |= reg_flag; return min; } @@ -4721,20 +4814,45 @@ FoxArm64Register FoxIRToArm64::RegisterRequest(FoxIRToArm64::RegisterUsage usage void FoxIRToArm64::RegisterRelease(FoxArm64Register reg) { - CurrentFrame.RegistersInUse &= ~(1 << reg); + GetCurrentFrame()->RegistersInUse &= ~(1 << reg); } - -void FoxIRToArm64::ResetFrame() +bool FoxIRToArm64::IsRegisterInUse(FoxArm64Register reg) { - std::memset(&CurrentFrame, 0, sizeof(CurrentFrame)); + return (GetCurrentFrame()->RegistersInUse & (1 << static_cast(reg))); } + FoxArm64Register FoxIRToArm64::GetGeneralRegFromIR(FoxIRRegister ir_reg) { return static_cast(static_cast(Fox_Arm64_W8) + static_cast(ir_reg)); } +FoxIRArm64Frame* FoxIRToArm64::GetCurrentFrame() +{ + if (mStackFrames.IsEmpty()) { + return nullptr; + } + + return &mStackFrames.GetLast(); +} + +FoxIRArm64Frame* FoxIRToArm64::FramePush() +{ + if (!mStackFrames.IsInited()) { + mStackFrames.Create(16); + } + + PreFrameStackAllocation = 0; + + return mStackFrames.Insert(); +} + +void FoxIRToArm64::FramePop() +{ + mStackFrames.RemoveLast(); +} + const char* FoxIRToArm64::GetRegisterName(FoxArm64Register reg) { diff --git a/FoxScript.hpp b/FoxScript.hpp index 654da6f..9690aa5 100644 --- a/FoxScript.hpp +++ b/FoxScript.hpp @@ -7,7 +7,7 @@ #define FX_SCRIPT_VERSION_MAJOR 0 #define FX_SCRIPT_VERSION_MINOR 3 -#define FX_SCRIPT_VERSION_PATCH 1 +#define FX_SCRIPT_VERSION_PATCH 2 #define FX_SCRIPT_VAR_RETURN_VAL "__ReturnVal__" @@ -256,6 +256,8 @@ struct FoxAstReturn : public FoxAstNode { this->NodeType = FX_AST_RETURN; } + + FoxAstNode* Rhs = nullptr; }; /** @@ -616,7 +618,13 @@ class FoxAstPrinter Print(command_mode->Node, depth + 1); } else if (node->NodeType == FX_AST_RETURN) { + FoxAstReturn* return_node = reinterpret_cast(node); + puts("[RETURN]"); + + if (return_node->Rhs) { + Print(return_node->Rhs, depth + 1); + } } else { puts("[UNKNOWN]"); @@ -1123,7 +1131,11 @@ class FoxIREmitter void EmitJumpAbsolute(uint32 position); void EmitJumpAbsoluteReg32(FoxIRRegister reg); void EmitJumpCallAbsolute(uint32 position); + void EmitJumpReturnToCaller(); + void EmitJumpReturnToCallerReg32(FoxIRRegister reg); + void EmitJumpReturnToCallerInt32(int32 value); + void EmitJumpCallExternal(FoxHash hashed_name); void EmitVariableGetInt32(uint16 var_index, FoxIRRegister dest_reg); @@ -1215,6 +1227,8 @@ class FoxIRPrinter struct FoxIRArm64Frame { uint32 StackAllocated = 0; + uint32 UnAlignedStackAllocated = 0; + uint32 RegistersInUse = 0; }; @@ -1279,21 +1293,28 @@ class FoxIRToArm64 void DoVariable(char* s, uint8 op_base, uint8 op_spec); private: - void ResetFrame(); + // void ResetFrame(); uint32 MakeValueFactorOf16(uint32 value); FoxArm64Register RegisterRequest(RegisterUsage usage); + bool IsRegisterInUse(FoxArm64Register reg); void RegisterRelease(FoxArm64Register reg); FoxArm64Register GetGeneralRegFromIR(FoxIRRegister ir_reg); const char* GetRegisterName(FoxArm64Register reg); + FoxIRArm64Frame* GetCurrentFrame(); + + FoxIRArm64Frame* FramePush(); + void FramePop(); + private: uint32 mBytecodeIndex = 0; FoxMPPagedArray mBytecode; - FoxIRArm64Frame CurrentFrame; + uint32 PreFrameStackAllocation = 0; + FoxMPPagedArray mStackFrames; }; diff --git a/FoxScriptBytecode.hpp b/FoxScriptBytecode.hpp index 214d1a7..4130ad1 100644 --- a/FoxScriptBytecode.hpp +++ b/FoxScriptBytecode.hpp @@ -140,7 +140,10 @@ enum IrSpecJump : uint8 IrSpecJump_AbsoluteReg32, IrSpecJump_CallAbsolute, + IrSpecJump_ReturnToCaller, + IrSpecJump_ReturnToCaller_Int32, + IrSpecJump_ReturnToCaller_Reg32, IrSpecJump_CallExternal, }; diff --git a/Main.fox b/Main.fox index ccb69e7..00f5a28 100644 --- a/Main.fox +++ b/Main.fox @@ -1,2 +1,7 @@ -local int x = 5; -local int y = x + 2; \ No newline at end of file +fn Get5() int +{ + return 5; +} + +local int x = Get5(); +local int y = x + 2; diff --git a/Test b/Test new file mode 100755 index 0000000000000000000000000000000000000000..07fbb525ad843399d69178331847e6531893b9ae GIT binary patch literal 33480 zcmeI*UuYaf90%~(+oZ{HO|Q{dA}ToqrJf;4n<`Qt+}OsZSd!322^N_o&0c%7vDn*4 zYbsvV2%=z9kQV%d;)50xq!j5rs3(F}5G10p)KU*YTrCYP3SuOl-{0)6y^BVX_VGLL zyWQW+&g^eKd++o4-1$G2DrG6O7@`r8x0RYyDcmV_EusgZb${1}?gzRz_epPcGn1>k z{+7u)K0@n(?!kfTVKd*U?o(l2i*5<2O`6u8yVncugS>jZB5IfQhQdcAuWB_aUzuy2 z^TtPVe|0UaFI5w)2P4xYk7|*Q`f$ByT=sbcq4oN%fiAtSuXjtZTPH-u)wBgyDN{mf zUyjgv`|gTuF1lVlo;A%0=7*VDf}6_ka_Kv6+Sq$<_xg>|H^?uj3%RtD;U;B`%5~P@ z?;-Vx;t(#KVLpVs1G!9VMjSyd-|Ygfci@^p^dqFnGf{xEYJC~6Y<|AlI~rStn-oIa z+sAWz+IM9~+DG^88bvPcI)u~_f6h8I^X{6{@Bh^FduG*5XI7&xg$VYPM3G5zZ~i8= z&)1|eX7-1xw3XPOtaHjdV7knYyjS)mV*%9$Y}dL}3+majFXy>qZFje!uIz}Jrf$YX z)<2lXe+SoF!d$$h-GGqsjsq|Zij?j}TX~(DE+tjLPdWv4jcPrP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=EpyxRL_-E4digq5uUb zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP~iUyq%fr)AxFZ?k>i!ej?4M%QIoUI zqh{_MoHFl3J>gtA3|+f>vtHP5X?2y{O24g6)!|N$?Z6Z6wsFtZJKW(>caMsX4QC%x z4N4X3njLxkM#M4{QpCCIQcr7`H=`iQWx1p!C#47Z3X=!tw9EMQLBHIZCi{>`Dg6(x z*XH#>+1~I@S7)-1xT%)ZE#nMZ9qeX|#3|`cRJbn2O;IF;m)u7#|F$#FaYG zk&2n4>cg&oy$pq;)_|My)T>wfiTLb`YsZp>I{zE%@Jshw2XAZm?34ReT^)VdU|K9Z?Lw!|M>n#Cr`ikY|k^TZ(Q#9w_lxm`r->2`?c03xBs%O zC3CSMapKF_*T2~MMCtoOvE%12cm4mG|KXe8-MZH8>6~jHekJ$RofGeret7t Date: Sat, 13 Sep 2025 19:46:17 -0300 Subject: [PATCH 6/9] Reduced branching dramatically in emitted IR --- FoxScript.cpp | 33 ++++++++++++++++++++++++++++----- FoxScript.hpp | 3 ++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/FoxScript.cpp b/FoxScript.cpp index 4062abd..36da812 100644 --- a/FoxScript.cpp +++ b/FoxScript.cpp @@ -3092,9 +3092,9 @@ void FoxIREmitter::Emit(FoxAstNode* node) if (node->NodeType == FX_AST_BLOCK) { return EmitBlock(reinterpret_cast(node)); } - else if (node->NodeType == FX_AST_ACTIONDECL) { - return EmitFunction(reinterpret_cast(node)); - } + // else if (node->NodeType == FX_AST_ACTIONDECL) { + // return EmitFunction(reinterpret_cast(node)); + // } else if (node->NodeType == FX_AST_ACTIONCALL) { return DoFunctionCall(reinterpret_cast(node)); } @@ -3997,10 +3997,21 @@ FoxBytecodeVarHandle* FoxIREmitter::DefineReturnVar(FoxAstVarDecl* decl) return DoVarDeclare(decl); } +void FoxIREmitter::EmitFunctionDefinitionsInBlock(FoxAstBlock* block) +{ + for (FoxAstNode* stmt : block->Statements) { + if (stmt->NodeType == FX_AST_ACTIONDECL) { + EmitFunction(reinterpret_cast(stmt)); + } + } +} + void FoxIREmitter::EmitFunction(FoxAstFunctionDecl* function) { RETURN_IF_NO_NODE(function); + EmitFunctionDefinitionsInBlock(function->Block); + ++mScopeIndex; // Store the bytecode offset before the function is emitted @@ -4028,7 +4039,9 @@ void FoxIREmitter::EmitFunction(FoxAstFunctionDecl* function) // FoxBytecodeVarHandle* return_var = DefineReturnVar(function->ReturnVar); - EmitBlock(function->Block); + // Do not check if there are function definitions to be declared when emitting the block here as they are checked above, before any parameters + // or stack allocations are output. + EmitBlock(function->Block, true); // Check to see if there has been a return statement in the function bool block_has_return = false; @@ -4081,12 +4094,22 @@ void FoxIREmitter::EmitFunction(FoxAstFunctionDecl* function) } } -void FoxIREmitter::EmitBlock(FoxAstBlock* block) +void FoxIREmitter::EmitBlock(FoxAstBlock* block, bool ignore_function_definitions) { RETURN_IF_NO_NODE(block); + if (!ignore_function_definitions) { + // Before outputting any statements output any function definitions in the block. + EmitFunctionDefinitionsInBlock(block); + } + // For each var declared in the block, write a stack allocation in the frame header for (FoxAstNode* node : block->Statements) { + // Ignore function definitions when emitting the block statements as they are handled elsewhere! + if (node->NodeType == FX_AST_ACTIONDECL) { + continue; + } + if (node->NodeType == FX_AST_VARDECL) { FoxAstVarDecl* var_decl = reinterpret_cast(node); diff --git a/FoxScript.hpp b/FoxScript.hpp index 9690aa5..3e968eb 100644 --- a/FoxScript.hpp +++ b/FoxScript.hpp @@ -1095,8 +1095,9 @@ class FoxIREmitter private: - void EmitBlock(FoxAstBlock* block); + void EmitBlock(FoxAstBlock* block, bool ignore_function_definitions = false); void EmitFunction(FoxAstFunctionDecl* function); + void EmitFunctionDefinitionsInBlock(FoxAstBlock* block); void DoFunctionCall(FoxAstFunctionCall* call); FoxBytecodeVarHandle* DoVarDeclare(FoxAstVarDecl* decl, VarDeclareMode mode = DECLARE_DEFAULT); void EmitAssign(FoxAstAssign* assign); From 8260b55bc1665aa805b0b7ffb6ae0e1909c39797 Mon Sep 17 00:00:00 2001 From: Ethan MacDonald Date: Sat, 13 Sep 2025 20:55:10 -0300 Subject: [PATCH 7/9] Compiler output now working for arm64 with function definitions, calls, and addition --- FoxScript.cpp | 97 +++++++++++++++++++++++++++++++++++-------- FoxScript.hpp | 12 +++++- FoxScriptBytecode.hpp | 2 + Test.asm | 52 +++++++++++------------ 4 files changed, 116 insertions(+), 47 deletions(-) diff --git a/FoxScript.cpp b/FoxScript.cpp index 36da812..b20269e 100644 --- a/FoxScript.cpp +++ b/FoxScript.cpp @@ -3230,6 +3230,8 @@ const char* FoxIREmitter::GetRegisterName(FoxIRRegister reg) return "GX3"; case FX_IR_SP: return "SP"; + case FX_IR_REG_RETURN_VALUE: + return "RETVAL"; default:; }; @@ -3788,7 +3790,7 @@ FoxIRRegister FoxIREmitter::EmitRhs(FoxAstNode* rhs, FoxIREmitter::RhsMode mode, else if (rhs->NodeType == FX_AST_ACTIONCALL) { DoFunctionCall(reinterpret_cast(rhs)); // Function results are stored in XR - result_register = FX_IR_GW3; + result_register = FX_IR_REG_RETURN_VALUE; } @@ -4077,7 +4079,7 @@ void FoxIREmitter::EmitFunction(FoxAstFunctionDecl* function) // mBytecode[header_jump_start_index] = static_cast(distance_to_function >> 8); // mBytecode[header_jump_start_index + 1] = static_cast((distance_to_function & 0xFF)); - FoxBytecodeFunctionHandle function_handle {.HashedName = function->Name->GetHash(), .BytecodeIndex = static_cast(start_of_function + 4)}; + FoxBytecodeFunctionHandle function_handle {.HashedName = function->Name->GetHash(), .BytecodeIndex = static_cast(start_of_function)}; const size_t number_of_scope_var_handles = VarHandles.Size() - start_var_handle_count; printf("Number of var handles to remove: %zu\n", number_of_scope_var_handles); @@ -4098,6 +4100,16 @@ void FoxIREmitter::EmitBlock(FoxAstBlock* block, bool ignore_function_definition { RETURN_IF_NO_NODE(block); + bool will_emit_entrypoint = false; + + if (!mEntryPointEmitted) { + will_emit_entrypoint = true; + + // We are going to emit the entry point at the end when we emit this block, but we dont want the function definitions in it to leech and steal + // our entry marker. + mEntryPointEmitted = true; + } + if (!ignore_function_definitions) { // Before outputting any statements output any function definitions in the block. EmitFunctionDefinitionsInBlock(block); @@ -4132,6 +4144,10 @@ void FoxIREmitter::EmitBlock(FoxAstBlock* block, bool ignore_function_definition } } + if (will_emit_entrypoint) { + EmitMarker(IrSpecMarker_EntryPoint); + } + // After the stack allocations, mark the start of the frame. EmitMarker(IrSpecMarker_FrameBegin); @@ -4356,13 +4372,16 @@ void FoxIRPrinter::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) void FoxIRPrinter::DoMarker(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == IrSpecMarker_FrameBegin) { - BC_PRINT_OP("frame begin"); + BC_PRINT_OP("@FrameBegin"); } else if (op_spec == IrSpecMarker_FrameEnd) { - BC_PRINT_OP("frame end"); + BC_PRINT_OP("@FrameEnd"); } else if (op_spec == IrSpecMarker_ParamsBegin) { - BC_PRINT_OP("params begin"); + BC_PRINT_OP("@Params"); + } + else if (op_spec == IrSpecMarker_EntryPoint) { + BC_PRINT_OP("@Entry"); } } @@ -4522,8 +4541,8 @@ void FoxIRToArm64::DoArith(char* s, uint8 op_base, uint8 op_spec) // BC_PRINT_OP("add [i32] %s, %s", FoxIREmitter::GetRegisterName(static_cast(a_reg)), // FoxIREmitter::GetRegisterName(static_cast(b_reg))); - const char* lhs_reg = GetRegisterName(GetGeneralRegFromIR(a_reg)); - const char* rhs_reg = GetRegisterName(GetGeneralRegFromIR(b_reg)); + const char* lhs_reg = GetRegisterName(GetArmRegFromIRReg(a_reg)); + const char* rhs_reg = GetRegisterName(GetArmRegFromIRReg(b_reg)); BC_PRINT_OP("add %s, %s, %s", lhs_reg, lhs_reg, rhs_reg); } @@ -4560,6 +4579,11 @@ void FoxIRToArm64::DoSave(char* s, uint8 op_base, uint8 op_spec) } } +void FoxIRToArm64::EmitFrameRestore() +{ + printf("add sp, sp, #%u\n", GetCurrentFrame()->StackAllocated + 16); +} + void FoxIRToArm64::DoJump(char* s, uint8 op_base, uint8 op_spec) { if (op_spec == IrSpecJump_Relative) { @@ -4577,20 +4601,28 @@ void FoxIRToArm64::DoJump(char* s, uint8 op_base, uint8 op_spec) } else if (op_spec == IrSpecJump_CallAbsolute) { uint32 position = Read32(); - BC_PRINT_OP("calla %u", position); + BC_PRINT_OP("bl _R_%u", position); } else if (op_spec == IrSpecJump_ReturnToCaller) { + GetCurrentFrame()->HasBaselevelReturnStmt = true; + EmitFrameRestore(); BC_PRINT_OP("ret"); } else if (op_spec == IrSpecJump_ReturnToCaller_Reg32) { - const FoxArm64Register value_reg = GetGeneralRegFromIR(static_cast(Read16())); + GetCurrentFrame()->HasBaselevelReturnStmt = true; + + const FoxArm64Register value_reg = GetArmRegFromIRReg(static_cast(Read16())); printf("mov w0, %s\n", GetRegisterName(value_reg)); + EmitFrameRestore(); BC_PRINT_OP("ret"); } else if (op_spec == IrSpecJump_ReturnToCaller_Int32) { + GetCurrentFrame()->HasBaselevelReturnStmt = true; + printf("mov w0, #%d\n", Read32()); + EmitFrameRestore(); BC_PRINT_OP("ret"); } @@ -4638,7 +4670,7 @@ void FoxIRToArm64::DoMove(char* s, uint8 op_base, uint8 op_spec_raw) if (op_spec == IrSpecMove_Int32) { int value = static_cast(Read32()); - const FoxArm64Register dest_reg = GetGeneralRegFromIR(static_cast(op_reg)); + const FoxArm64Register dest_reg = GetArmRegFromIRReg(static_cast(op_reg)); // BC_PRINT_OP("move [i32] %s, %u\t", FoxIREmitter::GetRegisterName(), value); @@ -4652,30 +4684,51 @@ void FoxIRToArm64::DoMarker(char* s, uint8 op_base, uint8 op_spec) uint32 stack_allocation = MakeValueFactorOf16(PreFrameStackAllocation); // Storage for the frame pointer and link register (x29 & x30) - stack_allocation += 16; FoxIRArm64Frame* current_frame = FramePush(); current_frame->StackAllocated = stack_allocation; - printf("sub sp, sp, #%u\n", current_frame->StackAllocated); + constexpr uint32 size_of_opcode = sizeof(uint16); + // The function definition index is the current bytecode index minus the size of an opcode, + // as the current opcode is loaded into memory(thus offsetting the bytecode index) + const uint32 function_bytecode_index = mBytecodeIndex - size_of_opcode; + + if (mEmitDefinitionAsEntryPoint) { + printf("_main:\n"); + } + else { + printf("_R_%d:\n", function_bytecode_index); + } + + // Allocate the stack frame + printf("sub sp, sp, #%u\n", current_frame->StackAllocated + 16); // Store the frame pointer and link address to the printf("stp x29, x30, [sp, #16]\n"); - // Move the SP back to ignore the storage for the above + // Move the FP back to ignore the storage for the above BC_PRINT_OP("add x29, sp, #16"); } else if (op_spec == IrSpecMarker_FrameEnd) { - BC_PRINT_OP("add sp, sp, #%u", GetCurrentFrame()->StackAllocated); - FramePop(); + // If there is a return statement on base level (without branching, conditions, etc.) then we can + // omit the frame restore logic here as it will already be covered by the return statement. + if (!GetCurrentFrame()->HasBaselevelReturnStmt) { + EmitFrameRestore(); + } + BC_PRINT_OP("// End of frame"); + FramePop(); // Reset the current stack frame } else if (op_spec == IrSpecMarker_ParamsBegin) { BC_PRINT_OP("// params begin"); } + else if (op_spec == IrSpecMarker_EntryPoint) { + mEmitDefinitionAsEntryPoint = true; + BC_PRINT_OP("// Entry point"); + } } @@ -4686,7 +4739,7 @@ void FoxIRToArm64::DoVariable(char* s, uint8 op_base, uint8 op_spec) // BC_PRINT_OP("vget [i32] $%d, %s", var_index, FoxIREmitter::GetRegisterName(dest_reg)); const FoxIRRegister dest_ir_reg = static_cast(Read16()); - const FoxArm64Register dest_reg = GetGeneralRegFromIR(dest_ir_reg); + const FoxArm64Register dest_reg = GetArmRegFromIRReg(dest_ir_reg); const uint32 var_stack_offset = GetCurrentFrame()->StackAllocated - ((var_index + 1) * 4); @@ -4715,7 +4768,7 @@ void FoxIRToArm64::DoVariable(char* s, uint8 op_base, uint8 op_spec) const uint32 var_stack_offset = GetCurrentFrame()->StackAllocated - ((var_index + 1) * 4); - BC_PRINT_OP("str %s, [sp, #%u]", GetRegisterName(GetGeneralRegFromIR(reg)), var_stack_offset); + BC_PRINT_OP("str %s, [sp, #%u]", GetRegisterName(GetArmRegFromIRReg(reg)), var_stack_offset); // BC_PRINT_OP("vset [r32] $%d, %s", var_index, FoxIREmitter::GetRegisterName(reg)); } } @@ -4723,6 +4776,7 @@ void FoxIRToArm64::DoVariable(char* s, uint8 op_base, uint8 op_spec) void FoxIRToArm64::Print() { + printf(".global _main\n\n"); while (mBytecodeIndex < mBytecode.Size()) { PrintOp(); } @@ -4846,8 +4900,15 @@ bool FoxIRToArm64::IsRegisterInUse(FoxArm64Register reg) } -FoxArm64Register FoxIRToArm64::GetGeneralRegFromIR(FoxIRRegister ir_reg) +FoxArm64Register FoxIRToArm64::GetArmRegFromIRReg(FoxIRRegister ir_reg) { + switch (ir_reg) { + case FX_IR_REG_RETURN_VALUE: + return Fox_Arm64_W0; + default: + break; + } + return static_cast(static_cast(Fox_Arm64_W8) + static_cast(ir_reg)); } diff --git a/FoxScript.hpp b/FoxScript.hpp index 3e968eb..16e9b70 100644 --- a/FoxScript.hpp +++ b/FoxScript.hpp @@ -693,6 +693,8 @@ enum FoxIRRegister : uint8 FX_IR_GX2, FX_IR_GX3, + FX_IR_REG_RETURN_VALUE, + /* Stack pointer */ FX_IR_SP, }; @@ -1187,6 +1189,8 @@ class FoxIREmitter uint16 mVarsInScope = 0; uint16 mScopeIndex = 0; + + bool mEntryPointEmitted = false; }; @@ -1230,6 +1234,8 @@ struct FoxIRArm64Frame uint32 StackAllocated = 0; uint32 UnAlignedStackAllocated = 0; + bool HasBaselevelReturnStmt = false; + uint32 RegistersInUse = 0; }; @@ -1293,6 +1299,8 @@ class FoxIRToArm64 void DoMarker(char* s, uint8 op_base, uint8 op_spec); void DoVariable(char* s, uint8 op_base, uint8 op_spec); + void EmitFrameRestore(); + private: // void ResetFrame(); @@ -1302,7 +1310,7 @@ class FoxIRToArm64 bool IsRegisterInUse(FoxArm64Register reg); void RegisterRelease(FoxArm64Register reg); - FoxArm64Register GetGeneralRegFromIR(FoxIRRegister ir_reg); + FoxArm64Register GetArmRegFromIRReg(FoxIRRegister ir_reg); const char* GetRegisterName(FoxArm64Register reg); @@ -1318,4 +1326,6 @@ class FoxIRToArm64 uint32 PreFrameStackAllocation = 0; FoxMPPagedArray mStackFrames; + + bool mEmitDefinitionAsEntryPoint = false; }; diff --git a/FoxScriptBytecode.hpp b/FoxScriptBytecode.hpp index 4130ad1..df7a361 100644 --- a/FoxScriptBytecode.hpp +++ b/FoxScriptBytecode.hpp @@ -172,6 +172,8 @@ enum IrSpecMarker : uint8 IrSpecMarker_ParamsBegin, + IrSpecMarker_EntryPoint, + }; enum IrSpecVariable : uint8 diff --git a/Test.asm b/Test.asm index 6874bbf..4151034 100644 --- a/Test.asm +++ b/Test.asm @@ -18,36 +18,32 @@ # .Lexit: // Bootstrap exit # mov w0, w8 # b _exit - .global _main -take_five: - sub sp, sp, #16 - str w0, [sp, #12] - ldr w8, [sp, #12] - add w0, w8, #5 - add sp, sp, #16 - ret - +_R_0: +sub sp, sp, #16 +stp x29, x30, [sp, #16] +add x29, sp, #16 // Offset: 0 +mov w0, #5 +add sp, sp, #16 +ret // Offset: 2 +// End of frame // Offset: 8 +// salloc 4 // Offset: 10 +// salloc 4 // Offset: 14 +// Entry point // Offset: 18 _main: - sub sp, sp, #32 - stp x29, x30, [sp, #16] - add x29, sp, #16 - mov w8, wzr - str w8, [sp] - stur wzr, [x29, #-4] - mov w0, #10 - bl take_five - mov w8, w0 - ldr w0, [sp] - str w8, [sp, #8] - ldr w8, [sp, #8] - add w8, w8, #2 - str w8, [sp, #4] - ldp x29, x30, [sp, #16] - add sp, sp, #32 - # ret - -.Lexit: // Bootstrap exit +sub sp, sp, #32 +stp x29, x30, [sp, #16] +add x29, sp, #16 // Offset: 20 +// params begin // Offset: 22 +bl _R_0 // Offset: 24 +str w0, [sp, #12] // Offset: 30 +ldr w8, [sp, #12] // Offset: 36 +mov w9, #2 // Offset: 42 +add w8, w8, w9 // Offset: 48 +str w8, [sp, #8] // Offset: 52 +add sp, sp, #32 +// End of frame // Offset: 58 +.Lexit: mov w0, w8 b _exit From 68f6f33be31b9a08a5b450b2b0b863946e8a6bfd Mon Sep 17 00:00:00 2001 From: Ethan MacDonald Date: Sat, 13 Sep 2025 22:09:32 -0300 Subject: [PATCH 8/9] Removed extra generated asm for functions that do not branch and functions that do not allocate on the stack --- FoxScript.cpp | 95 ++++++++++++++++++++++++++++++++---------- FoxScript.hpp | 4 +- FoxScriptBytecode.hpp | 2 +- Main.fox | 2 + Test.asm | 31 +++----------- Test.c | 13 ++++-- Test.s | 37 +++++++++------- a.out | Bin 0 -> 16872 bytes 8 files changed, 116 insertions(+), 68 deletions(-) create mode 100755 a.out diff --git a/FoxScript.cpp b/FoxScript.cpp index b20269e..8e35930 100644 --- a/FoxScript.cpp +++ b/FoxScript.cpp @@ -3125,13 +3125,18 @@ void FoxIREmitter::Emit(FoxAstNode* node) // Get the variable and load it into a register. FoxBytecodeVarHandle* var_to_return = FindVarHandle(var_ref->Name->GetHash()); - FoxIRRegister var_to_return_reg = FindFreeReg32(); + FoxIRRegister var_to_return_reg = FX_IR_REG_RETURN_VALUE; + MARK_REGISTER_USED(var_to_return_reg); if (var_to_return) { - DoLoad(var_to_return->Offset, var_to_return_reg); + EmitVariableGetInt32(var_to_return->VarIndexInScope, var_to_return_reg); } + // if (var_to_return) { + // DoLoad(var_to_return->Offset, var_to_return_reg); + // } + // Free the register as we will not need it after scope end MARK_REGISTER_FREE(var_to_return_reg); @@ -3913,7 +3918,6 @@ void FoxIREmitter::DoFunctionCall(FoxAstFunctionCall* call) FoxBytecodeFunctionHandle* handle = FindFunctionHandle(call->HashedName); - std::vector call_locations; call_locations.reserve(8); @@ -4115,14 +4119,18 @@ void FoxIREmitter::EmitBlock(FoxAstBlock* block, bool ignore_function_definition EmitFunctionDefinitionsInBlock(block); } + bool does_function_branch = false; + // For each var declared in the block, write a stack allocation in the frame header for (FoxAstNode* node : block->Statements) { // Ignore function definitions when emitting the block statements as they are handled elsewhere! if (node->NodeType == FX_AST_ACTIONDECL) { continue; } - - if (node->NodeType == FX_AST_VARDECL) { + else if (node->NodeType == FX_AST_ACTIONCALL) { + does_function_branch = true; + } + else if (node->NodeType == FX_AST_VARDECL) { FoxAstVarDecl* var_decl = reinterpret_cast(node); uint32 stack_index = mStackOffset; @@ -4151,6 +4159,10 @@ void FoxIREmitter::EmitBlock(FoxAstBlock* block, bool ignore_function_definition // After the stack allocations, mark the start of the frame. EmitMarker(IrSpecMarker_FrameBegin); + if (does_function_branch) { + EmitMarker(IrSpecMarker_FunctionBranches); + } + for (FoxAstNode* node : block->Statements) { Emit(node); @@ -4383,6 +4395,9 @@ void FoxIRPrinter::DoMarker(char* s, uint8 op_base, uint8 op_spec) else if (op_spec == IrSpecMarker_EntryPoint) { BC_PRINT_OP("@Entry"); } + else if (op_spec == IrSpecMarker_FunctionBranches) { + BC_PRINT_OP("@Branches"); + } } @@ -4581,11 +4596,29 @@ void FoxIRToArm64::DoSave(char* s, uint8 op_base, uint8 op_spec) void FoxIRToArm64::EmitFrameRestore() { - printf("add sp, sp, #%u\n", GetCurrentFrame()->StackAllocated + 16); + FoxIRArm64Frame* current_frame = GetCurrentFrame(); + + if (current_frame->DoesBranch) { + printf("ldp x29, x30, [sp, #%u]\n", GetCurrentFrame()->StackAllocated); + } + + if (current_frame->StackAllocated != 0 || current_frame->DoesBranch) { + int total_allocated = current_frame->StackAllocated; + + // If we do branch, we have saved the FP and LR registers to the stack. Each one is 8 bytes long (uint64), so we will need to keep that in + // mind when restoring the stack frame. + if (current_frame->DoesBranch) { + total_allocated += sizeof(uint64) * 2; + } + + printf("add sp, sp, #%u\n", total_allocated); + } } void FoxIRToArm64::DoJump(char* s, uint8 op_base, uint8 op_spec) { + FoxIRArm64Frame* current_frame = GetCurrentFrame(); + if (op_spec == IrSpecJump_Relative) { uint16 offset = Read16(); printf("// jump relative to (%u)\n", mBytecodeIndex + offset); @@ -4603,33 +4636,36 @@ void FoxIRToArm64::DoJump(char* s, uint8 op_base, uint8 op_spec) uint32 position = Read32(); BC_PRINT_OP("bl _R_%u", position); } + else if (op_spec == IrSpecJump_CallExternal) { + uint32 hashed_name = Read32(); + + BC_PRINT_OP("callext %u", hashed_name); + } else if (op_spec == IrSpecJump_ReturnToCaller) { - GetCurrentFrame()->HasBaselevelReturnStmt = true; + current_frame->HasBaselevelReturnStmt = true; EmitFrameRestore(); BC_PRINT_OP("ret"); } else if (op_spec == IrSpecJump_ReturnToCaller_Reg32) { - GetCurrentFrame()->HasBaselevelReturnStmt = true; + current_frame->HasBaselevelReturnStmt = true; const FoxArm64Register value_reg = GetArmRegFromIRReg(static_cast(Read16())); - printf("mov w0, %s\n", GetRegisterName(value_reg)); + if (value_reg != Fox_Arm64_W0) { + printf("mov w0, %s\n", GetRegisterName(value_reg)); + } + EmitFrameRestore(); BC_PRINT_OP("ret"); } else if (op_spec == IrSpecJump_ReturnToCaller_Int32) { - GetCurrentFrame()->HasBaselevelReturnStmt = true; + current_frame->HasBaselevelReturnStmt = true; printf("mov w0, #%d\n", Read32()); EmitFrameRestore(); BC_PRINT_OP("ret"); } - - else if (op_spec == IrSpecJump_CallExternal) { - uint32 hashed_name = Read32(); - BC_PRINT_OP("callext %u", hashed_name); - } } @@ -4701,14 +4737,27 @@ void FoxIRToArm64::DoMarker(char* s, uint8 op_base, uint8 op_spec) printf("_R_%d:\n", function_bytecode_index); } - // Allocate the stack frame - printf("sub sp, sp, #%u\n", current_frame->StackAllocated + 16); + // If there are no stack allocations and the current frame does not branch, do not create a new stack frame. + if (current_frame->StackAllocated != 0 || current_frame->DoesBranch) { + int total_allocated = current_frame->StackAllocated; - // Store the frame pointer and link address to the - printf("stp x29, x30, [sp, #16]\n"); + // If we do branch, we need to save the FP and LR registers to the stack. Each one is 8 bytes long (uint64). + if (current_frame->DoesBranch) { + total_allocated += sizeof(uint64) * 2; + } + + // Allocate the stack frame + printf("sub sp, sp, #%u\n", total_allocated); + } - // Move the FP back to ignore the storage for the above - BC_PRINT_OP("add x29, sp, #16"); + if (current_frame->DoesBranch) { + printf("stp x29, x30, [sp, #%u]\n", current_frame->StackAllocated); + // Move the FP back to ignore the storage for the above + BC_PRINT_OP("add x29, sp, #16"); + } + else { + BC_PRINT_OP(""); + } } else if (op_spec == IrSpecMarker_FrameEnd) { // If there is a return statement on base level (without branching, conditions, etc.) then we can @@ -4729,6 +4778,10 @@ void FoxIRToArm64::DoMarker(char* s, uint8 op_base, uint8 op_spec) mEmitDefinitionAsEntryPoint = true; BC_PRINT_OP("// Entry point"); } + else if (op_spec == IrSpecMarker_FunctionBranches) { + GetCurrentFrame()->DoesBranch = true; + BC_PRINT_OP("// Branches"); + } } diff --git a/FoxScript.hpp b/FoxScript.hpp index 16e9b70..6a8f832 100644 --- a/FoxScript.hpp +++ b/FoxScript.hpp @@ -1233,10 +1233,10 @@ struct FoxIRArm64Frame { uint32 StackAllocated = 0; uint32 UnAlignedStackAllocated = 0; + uint32 RegistersInUse = 0; bool HasBaselevelReturnStmt = false; - - uint32 RegistersInUse = 0; + bool DoesBranch = false; }; diff --git a/FoxScriptBytecode.hpp b/FoxScriptBytecode.hpp index df7a361..395adee 100644 --- a/FoxScriptBytecode.hpp +++ b/FoxScriptBytecode.hpp @@ -173,7 +173,7 @@ enum IrSpecMarker : uint8 IrSpecMarker_ParamsBegin, IrSpecMarker_EntryPoint, - + IrSpecMarker_FunctionBranches, }; enum IrSpecVariable : uint8 diff --git a/Main.fox b/Main.fox index 00f5a28..4da2949 100644 --- a/Main.fox +++ b/Main.fox @@ -5,3 +5,5 @@ fn Get5() int local int x = Get5(); local int y = x + 2; + +return y; diff --git a/Test.asm b/Test.asm index 4151034..7e7c22b 100644 --- a/Test.asm +++ b/Test.asm @@ -1,30 +1,11 @@ -# .global _main -# _main: -# // salloc 4 // Offset: 0 -# // salloc 4 // Offset: 4 -# sub sp, sp, #32 // Offset: 8 - -# stp x30, x29, [sp, #16] -# add sp, sp, #16 - -# mov w8, #5 -# str w8, [sp, #12] // Offset: 10 -# ldr w8, [sp, #12] // Offset: 18 -# mov w9, #2 // Offset: 24 -# add w8, w8, w9 // Offset: 30 -# str w8, [sp, #8] // Offset: 34 -# add sp, sp, #16 // Offset: 40 - -# .Lexit: // Bootstrap exit -# mov w0, w8 -# b _exit .global _main _R_0: sub sp, sp, #16 -stp x29, x30, [sp, #16] +stp x29, x30, [sp, #0] add x29, sp, #16 // Offset: 0 mov w0, #5 +ldp x29, x30, [sp, #0] add sp, sp, #16 ret // Offset: 2 // End of frame // Offset: 8 @@ -42,8 +23,8 @@ ldr w8, [sp, #12] // Offset: 36 mov w9, #2 // Offset: 42 add w8, w8, w9 // Offset: 48 str w8, [sp, #8] // Offset: 52 +ldr w0, [sp, #8] // Offset: 58 +ldp x29, x30, [sp, #16] add sp, sp, #32 -// End of frame // Offset: 58 -.Lexit: - mov w0, w8 - b _exit +ret // Offset: 64 +// End of frame // Offset: 68 diff --git a/Test.c b/Test.c index d3625a2..cd8af09 100644 --- a/Test.c +++ b/Test.c @@ -1,12 +1,17 @@ -int some_function(int x) +int Get2() { - return x + 5; + return 2; +} + +int Get5() +{ + return Get2() + 5; } int main() { - int x = some_function(10); + int x = Get5(); int y = x + 2; - return 0; + return y; } diff --git a/Test.s b/Test.s index 44b36dd..c90a6a8 100644 --- a/Test.s +++ b/Test.s @@ -1,16 +1,27 @@ .section __TEXT,__text,regular,pure_instructions .build_version macos, 15, 0 sdk_version 15, 5 - .globl _some_function ; -- Begin function some_function + .globl _Get2 ; -- Begin function Get2 .p2align 2 -_some_function: ; @some_function +_Get2: ; @Get2 .cfi_startproc ; %bb.0: - sub sp, sp, #16 - .cfi_def_cfa_offset 16 - str w0, [sp, #12] - ldr w8, [sp, #12] - add w0, w8, #5 - add sp, sp, #16 + mov w0, #2 ; =0x2 + ret + .cfi_endproc + ; -- End function + .globl _Get5 ; -- Begin function Get5 + .p2align 2 +_Get5: ; @Get5 + .cfi_startproc +; %bb.0: + stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill + mov x29, sp + .cfi_def_cfa w29, 16 + .cfi_offset w30, -8 + .cfi_offset w29, -16 + bl _Get2 + add w0, w0, #5 + ldp x29, x30, [sp], #16 ; 16-byte Folded Reload ret .cfi_endproc ; -- End function @@ -25,17 +36,13 @@ _main: ; @main .cfi_def_cfa w29, 16 .cfi_offset w30, -8 .cfi_offset w29, -16 - mov w8, #0 ; =0x0 - str w8, [sp] ; 4-byte Folded Spill stur wzr, [x29, #-4] - mov w0, #10 ; =0xa - bl _some_function - mov x8, x0 - ldr w0, [sp] ; 4-byte Folded Reload - str w8, [sp, #8] + bl _Get5 + str w0, [sp, #8] ldr w8, [sp, #8] add w8, w8, #2 str w8, [sp, #4] + ldr w0, [sp, #4] ldp x29, x30, [sp, #16] ; 16-byte Folded Reload add sp, sp, #32 ret diff --git a/a.out b/a.out new file mode 100755 index 0000000000000000000000000000000000000000..aeaac6aa4c89e1c84af8b43af3db3a597069cddc GIT binary patch literal 16872 zcmeI4K}b|l6o$_mXFwa935!rFm_>v|IZ`eZik{h^R-~DWA($?jFBCOH$Iu*TFkDDb z7(p%qC4v%?BH9dTxTt8CZfX(<2_l19B?c4Ybk2Kk&`E4jE&l^&&OP_sd+vX~x4!cx z@ohPmNFz1}`zH2b9t@C=M??keRqRUDmRAPO1nO#JHq*?_nNw>r=`+l(RDB>=pIJ8d z>zQ+8=PsTWPoJSw*ystbto^-ToVCl^T6>A)8Rn$u>U`yXC#p{#4;-ydYt!vBIhtn2 z1zU)Ov?i&S5JiQZ=q}}Oz|KoKFXmiiD7K$;Zy$ zl>FUYo&L6#Mt@UpTNCGE+t@{iF*o~oq@wKWU_t1ouTV?w=Q$s{btf-F_nKo$sVJ*RuS!bW@1ks{XB(r9ho#XqOZc zciXw}65GKp^=X}ZTOv7I-%=GclkB6hWCab4QnW7Fr;qX6&{URso4P7B&8#h@Qn%;5 z6kG7>v1(qIt>w5E+!UL4>#<~C`53P?_pE;sDj)y?AOHd&00JNY0w4eaAOHd&00JNY z0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4eaAOHd&00JNY0w4ea zAOHd&00JNY0w4eaAn^YP__$TE?b3Di^Xhfqp=*lrWU=*FeUTq|J5+nKGJ1@2-C;vD z8x2iHC*`y^v|ON#L~+-4Sxxfm;RDj|^kutOvtE|Vxm(TLdRH#FkN+`XZChowRdq^a zXISDx?iAlZq{()%Ej%a3ER(}2dS!f;J;*M`()DSd!+bJt&HVYd)-G!eMIGH?io6cY zO@92``eNV9>AbSUqf75^K8x?{A0Ih*Cz|&>5+A?v@JX=a)tB>A&UZ62t&W Date: Sat, 13 Sep 2025 22:44:48 -0300 Subject: [PATCH 9/9] Added IR directive 'Branches' for stack frames, fixed issue with prior optimization --- FoxScript.cpp | 76 +++++++++++++++++++++++++++++++++++++++----------- FoxScript.hpp | 4 ++- Test.asm | 29 +++++++++---------- a.out | Bin 16872 -> 16872 bytes 4 files changed, 76 insertions(+), 33 deletions(-) diff --git a/FoxScript.cpp b/FoxScript.cpp index 8e35930..cf84b69 100644 --- a/FoxScript.cpp +++ b/FoxScript.cpp @@ -4114,22 +4114,23 @@ void FoxIREmitter::EmitBlock(FoxAstBlock* block, bool ignore_function_definition mEntryPointEmitted = true; } + bool does_block_branch = false; + if (!ignore_function_definitions) { // Before outputting any statements output any function definitions in the block. EmitFunctionDefinitionsInBlock(block); } - bool does_function_branch = false; - // For each var declared in the block, write a stack allocation in the frame header for (FoxAstNode* node : block->Statements) { + if (!does_block_branch && DoesNodeBranch(node)) { + does_block_branch = true; + } + // Ignore function definitions when emitting the block statements as they are handled elsewhere! if (node->NodeType == FX_AST_ACTIONDECL) { continue; } - else if (node->NodeType == FX_AST_ACTIONCALL) { - does_function_branch = true; - } else if (node->NodeType == FX_AST_VARDECL) { FoxAstVarDecl* var_decl = reinterpret_cast(node); @@ -4156,14 +4157,14 @@ void FoxIREmitter::EmitBlock(FoxAstBlock* block, bool ignore_function_definition EmitMarker(IrSpecMarker_EntryPoint); } - // After the stack allocations, mark the start of the frame. - EmitMarker(IrSpecMarker_FrameBegin); - - if (does_function_branch) { + if (does_block_branch) { EmitMarker(IrSpecMarker_FunctionBranches); } + // After the stack allocations, mark the start of the frame. + EmitMarker(IrSpecMarker_FrameBegin); + for (FoxAstNode* node : block->Statements) { Emit(node); } @@ -4194,6 +4195,46 @@ void FoxIREmitter::PrintBytecode() printf("\n"); } +bool FoxIREmitter::DoesNodeBranch(FoxAstNode* node) +{ + if (node == nullptr) { + return false; + } + + if (node->NodeType == FX_AST_ACTIONCALL) { + return true; + } + + else if (node->NodeType == FX_AST_BLOCK) { + FoxAstBlock* block = reinterpret_cast(node); + for (FoxAstNode* stmt : block->Statements) { + if (DoesNodeBranch(stmt)) { + return true; + } + } + + return false; + } + + else if (node->NodeType == FX_AST_VARDECL) { + FoxAstVarDecl* vardecl = reinterpret_cast(node); + + return DoesNodeBranch(vardecl->Assignment); + } + else if (node->NodeType == FX_AST_BINOP) { + FoxAstBinop* binop = reinterpret_cast(node); + return (DoesNodeBranch(binop->Left) || DoesNodeBranch(binop->Right)); + } + + else if (node->NodeType == FX_AST_ASSIGN) { + FoxAstAssign* assign = reinterpret_cast(node); + + return DoesNodeBranch(assign->Rhs); + } + + return false; +} + #pragma endregion IrEmitter @@ -4598,21 +4639,23 @@ void FoxIRToArm64::EmitFrameRestore() { FoxIRArm64Frame* current_frame = GetCurrentFrame(); - if (current_frame->DoesBranch) { + if (mFunctionContainsBranches) { printf("ldp x29, x30, [sp, #%u]\n", GetCurrentFrame()->StackAllocated); } - if (current_frame->StackAllocated != 0 || current_frame->DoesBranch) { + if (current_frame->StackAllocated != 0 || mFunctionContainsBranches) { int total_allocated = current_frame->StackAllocated; // If we do branch, we have saved the FP and LR registers to the stack. Each one is 8 bytes long (uint64), so we will need to keep that in // mind when restoring the stack frame. - if (current_frame->DoesBranch) { + if (mFunctionContainsBranches) { total_allocated += sizeof(uint64) * 2; } printf("add sp, sp, #%u\n", total_allocated); } + + mFunctionContainsBranches = false; } void FoxIRToArm64::DoJump(char* s, uint8 op_base, uint8 op_spec) @@ -4738,11 +4781,11 @@ void FoxIRToArm64::DoMarker(char* s, uint8 op_base, uint8 op_spec) } // If there are no stack allocations and the current frame does not branch, do not create a new stack frame. - if (current_frame->StackAllocated != 0 || current_frame->DoesBranch) { + if (current_frame->StackAllocated != 0 || mFunctionContainsBranches) { int total_allocated = current_frame->StackAllocated; // If we do branch, we need to save the FP and LR registers to the stack. Each one is 8 bytes long (uint64). - if (current_frame->DoesBranch) { + if (mFunctionContainsBranches) { total_allocated += sizeof(uint64) * 2; } @@ -4750,7 +4793,7 @@ void FoxIRToArm64::DoMarker(char* s, uint8 op_base, uint8 op_spec) printf("sub sp, sp, #%u\n", total_allocated); } - if (current_frame->DoesBranch) { + if (mFunctionContainsBranches) { printf("stp x29, x30, [sp, #%u]\n", current_frame->StackAllocated); // Move the FP back to ignore the storage for the above BC_PRINT_OP("add x29, sp, #16"); @@ -4779,7 +4822,8 @@ void FoxIRToArm64::DoMarker(char* s, uint8 op_base, uint8 op_spec) BC_PRINT_OP("// Entry point"); } else if (op_spec == IrSpecMarker_FunctionBranches) { - GetCurrentFrame()->DoesBranch = true; + mFunctionContainsBranches = true; + BC_PRINT_OP("// Branches"); } } diff --git a/FoxScript.hpp b/FoxScript.hpp index 6a8f832..5cf5b6a 100644 --- a/FoxScript.hpp +++ b/FoxScript.hpp @@ -1176,6 +1176,8 @@ class FoxIREmitter void MarkRegisterUsed(FoxIRRegister reg); void MarkRegisterFree(FoxIRRegister reg); + bool DoesNodeBranch(FoxAstNode* node); + public: FoxMPPagedArray VarHandles; std::vector FunctionHandles; @@ -1236,7 +1238,6 @@ struct FoxIRArm64Frame uint32 RegistersInUse = 0; bool HasBaselevelReturnStmt = false; - bool DoesBranch = false; }; @@ -1328,4 +1329,5 @@ class FoxIRToArm64 FoxMPPagedArray mStackFrames; bool mEmitDefinitionAsEntryPoint = false; + bool mFunctionContainsBranches = false; }; diff --git a/Test.asm b/Test.asm index 7e7c22b..18d9e47 100644 --- a/Test.asm +++ b/Test.asm @@ -1,30 +1,27 @@ .global _main _R_0: -sub sp, sp, #16 -stp x29, x30, [sp, #0] -add x29, sp, #16 // Offset: 0 + // Offset: 0 mov w0, #5 -ldp x29, x30, [sp, #0] -add sp, sp, #16 ret // Offset: 2 // End of frame // Offset: 8 // salloc 4 // Offset: 10 // salloc 4 // Offset: 14 // Entry point // Offset: 18 +// Branches // Offset: 20 _main: sub sp, sp, #32 stp x29, x30, [sp, #16] -add x29, sp, #16 // Offset: 20 -// params begin // Offset: 22 -bl _R_0 // Offset: 24 -str w0, [sp, #12] // Offset: 30 -ldr w8, [sp, #12] // Offset: 36 -mov w9, #2 // Offset: 42 -add w8, w8, w9 // Offset: 48 -str w8, [sp, #8] // Offset: 52 -ldr w0, [sp, #8] // Offset: 58 +add x29, sp, #16 // Offset: 22 +// params begin // Offset: 24 +bl _R_0 // Offset: 26 +str w0, [sp, #12] // Offset: 32 +ldr w8, [sp, #12] // Offset: 38 +mov w9, #2 // Offset: 44 +add w8, w8, w9 // Offset: 50 +str w8, [sp, #8] // Offset: 54 +ldr w0, [sp, #8] // Offset: 60 ldp x29, x30, [sp, #16] add sp, sp, #32 -ret // Offset: 64 -// End of frame // Offset: 68 +ret // Offset: 66 +// End of frame // Offset: 70 diff --git a/a.out b/a.out index aeaac6aa4c89e1c84af8b43af3db3a597069cddc..efa2bc29b9bb53bff0f3ddef32b1c23346fc8d1d 100755 GIT binary patch delta 185 zcmaFS%=n_2al#Eon~gW+83mR|dYWHvweOlBQa$OMW!kaH984CB4<J@s~K1Rb!M3Odov?5v+d*!j3Sd+9Grm)Jsgx6IVNX2=mOa@9cJm;v_W=Vc7>8RF^YfHi(Cq2mnqEMr8m1 delta 201 zcmaFS%=n_2al#G8fQ>ih83j`B+}beT+44=NWbAJR4aUEdIhZUMzf5*yny&fZnc?E! zYKE16of#%BU}y;XTkWtCC^qo`bNsdc%^*2Ou-v!JZ<&~FC$l&>12uX$C^5=R&UVlR zvS&KX(hp#O0LDbU{L&JJniH;f_C9)^eMI-@1tH5{>&tFV+I>T%Y3+QQISoSlYHmzU sa!gSBHN`}uFZPDLu!-%SJD