diff --git a/control.hh b/control.hh index e41f008..c03de1b 100644 --- a/control.hh +++ b/control.hh @@ -38,6 +38,8 @@ enum E_OpType M_LSHIFT_OP( T_StringBuilder , E_OpType ); uint32_t ArgumentsFor( E_OpType op ) noexcept; +int32_t DeltaMainStack( E_OpType op ) noexcept; +int32_t DeltaFPUStack( E_OpType op ) noexcept; struct T_Op diff --git a/opcomp.cc b/opcomp.cc index 9362d3d..0bd1cd8 100644 --- a/opcomp.cc +++ b/opcomp.cc @@ -56,6 +56,8 @@ struct T_CompilerImpl_ E_OpType op , uint32_t arg0 , uint32_t arg1 , T_SRDLocation const& location ) noexcept; + void applyStackEffects( + T_Op const& op ) noexcept; }; @@ -318,22 +320,17 @@ bool T_CompilerImpl_::compileNode( if ( !main ) { addInstruction( OP_PUSH , node.location( ) ); addInstruction( OP_FP_SSTORE , 0 , node.location( ) ); - sdMain ++; - sdFPU --; } return false; } else if ( exit && !n.isIdentifier( ) ) { addInstruction( OP_PUSH , node.location( ) ); addInstruction( OP_FP_SSTORE , 0 , node.location( ) ); - sdMain ++; - sdFPU --; } break; } case A_Node::OP_SET: if ( exit ) { - assert( sdFPU > 0 ); auto& id( ((T_SetInstrNode&)node).id( ) ); auto& func{ input->root.function( funcIndex ) }; if ( func.hasLocal( id ) ) { @@ -345,13 +342,11 @@ bool T_CompilerImpl_::compileNode( *locations.get( ((T_SetInstrNode&)node).id( ) ) , node.location( ) ); } - sdFPU --; } break; case A_Node::OP_COND: if ( exit ) { - assert( sdMain > 0 ); addInstruction( OP_POP , 0 , node.location( ) ); sdMain --; } @@ -361,8 +356,6 @@ bool T_CompilerImpl_::compileNode( if ( exit ) { addInstruction( OP_PUSH , node.location( ) ); addInstruction( OP_FP_SSTORE_INT , 0 , node.location( ) ); - sdFPU --; - sdMain ++; } break; @@ -395,30 +388,22 @@ bool T_CompilerImpl_::compileNode( case A_Node::EXPR_ADD: if ( exit ) { - assert( sdFPU > 2 ); addInstruction( OP_FP_ADD , node.location( ) ); - sdFPU --; } break; case A_Node::EXPR_SUB: if ( exit ) { - assert( sdFPU > 2 ); addInstruction( OP_FP_SUB , node.location( ) ); - sdFPU --; } break; case A_Node::EXPR_MUL: if ( exit ) { - assert( sdFPU > 2 ); addInstruction( OP_FP_MUL , node.location( ) ); - sdFPU --; } break; case A_Node::EXPR_DIV: if ( exit ) { - assert( sdFPU > 2 ); addInstruction( OP_FP_DIV , node.location( ) ); - sdFPU --; } break; @@ -429,7 +414,6 @@ bool T_CompilerImpl_::compileNode( addInstruction( OP_FP_LOAD , constants.indexOf( value.u ) + 3 , node.location( ) ); - sdFPU ++; } break; @@ -456,7 +440,7 @@ void T_CompilerImpl_::processFunction( addInstruction( OP_POP , lvars - 1 , location ); sdMain -= lvars; } - sdMain -= 1 + args; + sdMain -= args; addInstruction( OP_RET , args , location ); assert( sdMain == 0 ); } else { @@ -492,13 +476,11 @@ bool T_CompilerImpl_::processIdentifier( const auto p( sdMain - ( stackPos + 1 ) ); if ( dt == E_DataType::VARIABLE ) { addInstruction( OP_FP_SLOAD , p , node.location( ) ); - sdFPU ++; return false; } addInstruction( OP_SLOAD , p , node.location( ) ); addInstruction( OP_PUSH , node.location( ) ); - sdMain ++; return true; } @@ -509,14 +491,12 @@ bool T_CompilerImpl_::processIdentifier( if ( dt == E_DataType::VARIABLE || dt == E_DataType::BUILTIN ) { addInstruction( OP_FP_LOAD , *locations.get( node.id( ) ) , node.location( ) ); - sdFPU ++; return false; } addInstruction( OP_LOAD , *locations.get( node.id( ) ) , node.location( ) ); addInstruction( OP_PUSH , node.location( ) ); - sdMain ++; return true; } @@ -526,7 +506,7 @@ void T_CompilerImpl_::addInstruction( T_SRDLocation const& location ) noexcept { assert( ArgumentsFor( op ) == 0 ); - output->ops.addNew( op , location ); + applyStackEffects( output->ops.addNew( op , location ) ); } void T_CompilerImpl_::addInstruction( @@ -535,7 +515,7 @@ void T_CompilerImpl_::addInstruction( T_SRDLocation const& location ) noexcept { assert( ArgumentsFor( op ) == 1 ); - output->ops.addNew( op , location , arg0 ); + applyStackEffects( output->ops.addNew( op , location , arg0 ) ); } void T_CompilerImpl_::addInstruction( @@ -545,7 +525,31 @@ void T_CompilerImpl_::addInstruction( T_SRDLocation const& location ) noexcept { assert( ArgumentsFor( op ) == 2 ); - output->ops.addNew( op , location , arg0 , arg1 ); + applyStackEffects( output->ops.addNew( op , location , arg0 , arg1 ) ); +} + +void T_CompilerImpl_::applyStackEffects( + T_Op const& op ) noexcept +{ + const auto m( DeltaMainStack( op.op ) ); + const auto f( DeltaFPUStack( op.op ) ); + +#ifdef INVASIVE_TRACES + T_StringBuilder sb; + sb << "applying stack effects for (" << op << ") - sdMain " << sdMain + << " (" << m << ") sdFPU " << sdFPU << " (" << f << ")" << '\n' << '\0'; + printf( "%s" , sb.data( ) ); +#endif + + if ( m ) { + assert( m > 0 || sdMain >= uint32_t( -m ) ); + sdMain += m; + } + + if ( f ) { + assert( f > 0 || sdFPU >= uint32_t( -m ) ); + sdFPU += m; + } } } diff --git a/ops.cc b/ops.cc index 738bf5e..423a4f9 100644 --- a/ops.cc +++ b/ops.cc @@ -14,43 +14,98 @@ namespace { struct T_OpInfo { char const* name; - int nArgs; + uint32_t nArgs; + int32_t sdMain{ 0 }; + int32_t sdFPU{ 0 }; + uint32_t fpuReq{ 0 }; - T_OpInfo( char const* name , - int nArgs = 0 ) - : name( name ) , nArgs( nArgs ) - { } + 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 } ); + 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" } ); + 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 } ); - infos.add( E_OpType::OP_FP_SLOAD , T_OpInfo{ "fp-load-stack" , 1 } ); - infos.add( E_OpType::OP_FP_STORE , T_OpInfo{ "fp-store" , 1 } ); - infos.add( E_OpType::OP_FP_SSTORE , T_OpInfo{ "fp-store-stack" , 1 } ); - infos.add( E_OpType::OP_FP_SSTORE_INT , T_OpInfo{ "fp-store-stack-int" , 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 } ); - infos.add( E_OpType::OP_FP_ADD , T_OpInfo{ "fp-add" } ); - infos.add( E_OpType::OP_FP_SUB , T_OpInfo{ "fp-sub" } ); - infos.add( E_OpType::OP_FP_MUL , T_OpInfo{ "fp-mul" } ); - infos.add( E_OpType::OP_FP_DIV , T_OpInfo{ "fp-div" } ); - infos.add( E_OpType::OP_FP_MUL , T_OpInfo{ "fp-neg" } ); - infos.add( E_OpType::OP_FP_DIV , T_OpInfo{ "fp-inv" } ); + 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; })( ) }; @@ -64,6 +119,20 @@ uint32_t ops::ArgumentsFor( 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 ==========================================================*/