#include "externals.hh" #include "control.hh" #include "globals.hh" #include "sync.hh" using namespace ops; using namespace ebcl; /*= OPCODE INFORMATIONS ========================================================*/ namespace { struct T_OpInfo { char const* name; uint32_t nArgs; int32_t sdMain{ 0 }; int32_t sdFPU{ 0 }; uint32_t fpuReq{ 0 }; template< typename ... Mods > constexpr T_OpInfo( char const* name , uint32_t nArgs , Mods&&... mods ); constexpr T_OpInfo( char const* name ); }; template< typename ... Mods > constexpr void ApplyMods_( T_OpInfo& op , Mods&&... mods ); template< > constexpr void ApplyMods_( T_OpInfo& ) { } template< typename M0 , typename ... Mods > constexpr void ApplyMods_( T_OpInfo& op , M0&& mod , Mods&&... mods ) { mod.applyTo( op ); ApplyMods_( op , std::forward< Mods >( mods ) ... ); } template< typename ... Mods > constexpr T_OpInfo::T_OpInfo( char const* name , uint32_t nArgs , Mods&&... mods ) : name( name ) , nArgs( nArgs ) { ApplyMods_( *this , std::forward< Mods >( mods ) ... ); } constexpr T_OpInfo::T_OpInfo( char const* name ) : T_OpInfo( name , 0 ) {} struct OpStackMain { int32_t value; explicit constexpr OpStackMain( int32_t v ) : value( v ) { } constexpr void applyTo( T_OpInfo& op ) { op.sdMain = value; } }; struct OpStackFPU { int32_t value; explicit constexpr OpStackFPU( int32_t v ) : value( v ) { } constexpr void applyTo( T_OpInfo& op ) { op.sdFPU = value; } }; static T_KeyValueTable< E_OpType , T_OpInfo > OpInfoTable_{ ([]() { T_KeyValueTable< E_OpType , T_OpInfo > infos; infos.add( E_OpType::OP_END , T_OpInfo{ "end" } ); // infos.add( E_OpType::OP_CALL , T_OpInfo{ "call" , 1 } ); infos.add( E_OpType::OP_RET , T_OpInfo{ "ret" , 1 , OpStackMain{ -1 } } ); infos.add( E_OpType::OP_COND_JUMP , T_OpInfo{ "cond-jump" , 2 } ); // infos.add( E_OpType::OP_RES_STACK , T_OpInfo{ "res-stack" , 1 } ); infos.add( E_OpType::OP_PUSH , T_OpInfo{ "push" , 0 , OpStackMain{ 1 } } ); infos.add( E_OpType::OP_POP , T_OpInfo{ "pop" , 1 } ); // infos.add( E_OpType::OP_LOAD , T_OpInfo{ "load" , 1 } ); infos.add( E_OpType::OP_SLOAD , T_OpInfo{ "load-stack" , 1 } ); // infos.add( E_OpType::OP_FP_LOAD , T_OpInfo{ "fp-load" , 1 , OpStackFPU{ 1 } } ); infos.add( E_OpType::OP_FP_SLOAD , T_OpInfo{ "fp-load-stack" , 1 , OpStackFPU{ 1 } } ); infos.add( E_OpType::OP_FP_STORE , T_OpInfo{ "fp-store" , 1 , OpStackFPU{ -1 } } ); infos.add( E_OpType::OP_FP_SSTORE , T_OpInfo{ "fp-store-stack" , 1 , OpStackFPU{ -1 } } ); infos.add( E_OpType::OP_FP_SSTORE_INT , T_OpInfo{ "fp-store-stack-int" , 1 , OpStackFPU{ -1 } } ); // infos.add( E_OpType::OP_FP_CMP , T_OpInfo{ "fp-cmp" , 1 , OpStackFPU{ -1 } } ); infos.add( E_OpType::OP_FP_ADD , T_OpInfo{ "fp-add" , 0 , OpStackFPU{ -1 } } ); infos.add( E_OpType::OP_FP_SUB , T_OpInfo{ "fp-sub" , 0 , OpStackFPU{ -1 } } ); infos.add( E_OpType::OP_FP_MUL , T_OpInfo{ "fp-mul" , 0 , OpStackFPU{ -1 } } ); infos.add( E_OpType::OP_FP_DIV , T_OpInfo{ "fp-div" , 0 , OpStackFPU{ -1 } } ); infos.add( E_OpType::OP_FP_MUL , T_OpInfo{ "fp-neg" , 0 } ); infos.add( E_OpType::OP_FP_DIV , T_OpInfo{ "fp-inv" , 0 } ); return infos; })( ) }; } // namespace uint32_t ops::ArgumentsFor( const E_OpType op ) noexcept { assert( OpInfoTable_.contains( op ) ); return OpInfoTable_.get( op )->nArgs; } int32_t ops::DeltaMainStack( const E_OpType op ) noexcept { assert( OpInfoTable_.contains( op ) ); return OpInfoTable_.get( op )->sdMain; } int32_t ops::DeltaFPUStack( const E_OpType op ) noexcept { assert( OpInfoTable_.contains( op ) ); return OpInfoTable_.get( op )->sdFPU; } /*= STRING FORMATTING ==========================================================*/ T_StringBuilder& ops::operator<<( T_StringBuilder& sb , const E_OpType et ) { assert( OpInfoTable_.contains( et ) ); sb << OpInfoTable_.get( et )->name; return sb; } T_StringBuilder& ops::operator<<( T_StringBuilder& sb , T_Op const& op ) { sb << op.op; const auto args{ OpInfoTable_.get( op.op )->nArgs }; if ( args ) { sb << ' ' << op.arg0; if ( args == 2 ) { sb << ' ' << op.arg1; } } return sb; }