From 6c58e8669f90b8c1e994a009a4953536322bfee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sun, 12 Nov 2017 22:20:11 +0100 Subject: [PATCH] Compiler - Conditionals --- control.hh | 25 +++++++++++++---- demo.srd | 7 ++--- opcomp.cc | 82 ++++++++++++++++++++++++++++++++++++++++++++++-------- ops.cc | 12 ++++---- 4 files changed, 99 insertions(+), 27 deletions(-) diff --git a/control.hh b/control.hh index c03de1b..2550bc1 100644 --- a/control.hh +++ b/control.hh @@ -12,7 +12,9 @@ enum E_OpType // OP_CALL , OP_RET , - OP_COND_JUMP , + // + OP_SKIP , + OP_COND_SKIP , // OP_RES_STACK , OP_PUSH , @@ -44,17 +46,30 @@ int32_t DeltaFPUStack( E_OpType op ) noexcept; struct T_Op { + static constexpr int MAX_ARGS = 4; + E_OpType op; T_SRDLocation location; - uint32_t arg0 , arg1; + uint32_t args[ MAX_ARGS ]; T_Op( const E_OpType op , T_SRDLocation const& location , - const uint32_t arg0 = 0 , - const uint32_t arg1 = 0 ) noexcept + const uint32_t arg0 = 0 ) noexcept : op( op ) , location( location ) , - arg0( arg0 ) , arg1( arg1 ) + args{ arg0 } { } + + T_Op( const E_OpType op , + T_SRDLocation const& location , + std::initializer_list< uint32_t > a ) noexcept + : op( op ) , location( location ) + { + assert( a.size( ) <= MAX_ARGS ); + auto it = a.begin( ); + for ( auto i = 0u ; i < a.size( ) ; i ++ , ++it ) { + args[ i ] = *it; + } + } }; M_LSHIFT_OP( T_StringBuilder , T_Op const& ); diff --git a/demo.srd b/demo.srd index cf76984..987b74b 100644 --- a/demo.srd +++ b/demo.srd @@ -4,15 +4,14 @@ ( (set vp-height $height) (set vp-width (mul $height (div 16 9))) - (set vp-x (div (sub $width $vp-width) 2)) - (set vp-y 0) )( (set vp-width $width) (set vp-height (div $width (div 16 9))) - (set vp-y (div (sub $height $vp-height) 2)) - (set vp-x 0) ) ) + # Viewport location + (set vp-x (div (sub $width $vp-width) 2)) + (set vp-y (div (sub $height $vp-height) 2)) (program prg-fullscreen "fullscreen.v.glsl") diff --git a/opcomp.cc b/opcomp.cc index 0bd1cd8..264eb18 100644 --- a/opcomp.cc +++ b/opcomp.cc @@ -28,7 +28,31 @@ struct T_CompilerImpl_ fiSamplers , fiTextures; uint32_t sdMain , sdFPU; - T_AutoArray< uint32_t , 32 > condJumps; + + /* + * Conditionals look something like this: + * + * 01 { compute expression and push it } + * 02 skip-cond value-for-case-1 2 { 5 - 2 - 1 } + * 03 { case 1 code } + * 04 skip 6 { 11 - 4 - 1 } + * 05 skip-cond value-for-case-2 3 { 9 - 5 - 1 } + * 06 { case 2 code } + * 07 { case 2 code } + * 08 skip 2 { 11 - 8 - 1 } + * 09 { default case code } + * 10 { default case code } + * 11 pop 1 + * + * So, in order to adjust the skips once we know about them, + * we need to store the location of the previous skip-cond, + * and the locations of all end-of-case skips. + */ + struct T_CondInfo_ { + uint32_t prevCase; + T_AutoArray< uint32_t , 16 > caseEnds; + }; + T_AutoArray< T_CondInfo_ , 16 > condJumps; void gatherConstants( ) noexcept; void countAssets( ) noexcept; @@ -54,7 +78,7 @@ struct T_CompilerImpl_ T_SRDLocation const& location ) noexcept; void addInstruction( E_OpType op , - uint32_t arg0 , uint32_t arg1 , + std::initializer_list< uint32_t > args , T_SRDLocation const& location ) noexcept; void applyStackEffects( T_Op const& op ) noexcept; @@ -347,8 +371,20 @@ bool T_CompilerImpl_::compileNode( case A_Node::OP_COND: if ( exit ) { + // Update all skips + const auto cpos( output->ops.sizeOf( funcIndex ) ); + auto const& skips( condJumps.last( ).caseEnds ); + for ( auto i = 0u ; i < skips.size( ) ; i ++ ) { + const auto skip( skips[ i ] ); + assert( output->ops.get( funcIndex , skip ).op == OP_SKIP ); + output->ops.get( funcIndex , skip ).args[ 0 ] = ( cpos - skip - 1 ); + } + addInstruction( OP_POP , 0 , node.location( ) ); sdMain --; + condJumps.removeLast( ); + } else { + condJumps.addNew( ); } break; @@ -361,21 +397,46 @@ bool T_CompilerImpl_::compileNode( case A_Node::TN_CASE: if ( exit ) { + // Store a potential skip location + condJumps.last( ).caseEnds.add( output->ops.sizeOf( funcIndex ) ); + + // Update the initial skip const auto cpos( output->ops.sizeOf( funcIndex ) ); - const auto diff( cpos - condJumps.last( ) ); - output->ops.get( funcIndex , condJumps.last( ) ).arg1 = diff - 1; - condJumps.removeLast( ); + const auto ppos( condJumps.last( ).prevCase ); + const auto diff( cpos - ppos ); + assert( diff > 1 ); + output->ops.get( funcIndex , ppos ).args[ 1 ] = diff - 1; #ifdef INVASIVE_TRACES printf( "\tCOND JUMP UPDATED: %d\n" , diff - 1 ); #endif } else { + // If there is a previous skip location, insert the skip instruction + if ( !condJumps.last( ).caseEnds.empty( ) ) { + addInstruction( OP_SKIP , 0 , node.location( ) ); + const auto ppos( condJumps.last( ).prevCase ); + assert( output->ops.get( funcIndex , ppos ).op == OP_COND_SKIP ); + output->ops.get( funcIndex , ppos ).args[ 1 ] ++; + } + + // Add the conditional skip auto& c( (T_CondInstrNode::T_ValuedCase&) node ); - condJumps.add( output->ops.sizeOf( funcIndex ) ); - addInstruction( OP_COND_JUMP , 0 , c.value( ) , + condJumps.last( ).prevCase = output->ops.sizeOf( funcIndex ); + addInstruction( OP_COND_SKIP , { 0 , uint32_t( c.value( ) ) } , node.location( ) ); } break; + case A_Node::TN_DEFAULT: + // If there is a previous skip location, insert the skip instruction + // and update the previous conditional skip + if ( !( exit || condJumps.last( ).caseEnds.empty( ) ) ) { + addInstruction( OP_SKIP , 0 , node.location( ) ); + const auto ppos( condJumps.last( ).prevCase ); + assert( output->ops.get( funcIndex , ppos ).op == OP_COND_SKIP ); + output->ops.get( funcIndex , ppos ).args[ 1 ] ++; + } + break; + case A_Node::EXPR_CMP_EQ: case A_Node::EXPR_CMP_NE: case A_Node::EXPR_CMP_GT: case A_Node::EXPR_CMP_GE: case A_Node::EXPR_CMP_LT: case A_Node::EXPR_CMP_LE: @@ -520,12 +581,11 @@ void T_CompilerImpl_::addInstruction( void T_CompilerImpl_::addInstruction( const E_OpType op , - const uint32_t arg0 , - const uint32_t arg1 , + std::initializer_list< uint32_t > args , T_SRDLocation const& location ) noexcept { - assert( ArgumentsFor( op ) == 2 ); - applyStackEffects( output->ops.addNew( op , location , arg0 , arg1 ) ); + assert( ArgumentsFor( op ) == args.size( ) ); + applyStackEffects( output->ops.addNew( op , location , args ) ); } void T_CompilerImpl_::applyStackEffects( diff --git a/ops.cc b/ops.cc index 423a4f9..fbbf23a 100644 --- a/ops.cc +++ b/ops.cc @@ -84,7 +84,9 @@ static T_KeyValueTable< E_OpType , T_OpInfo > OpInfoTable_{ ([]() { // 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_SKIP , T_OpInfo{ "skip" , 1 } ); + infos.add( E_OpType::OP_COND_SKIP , T_OpInfo{ "cond-skip" , 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 } } ); @@ -150,13 +152,9 @@ T_StringBuilder& ops::operator<<( 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; - } + for ( auto i = 0u ; i < args ; i ++ ) { + sb << ' ' << op.args[ i ]; } return sb; }