Compiler - Conditionals

This commit is contained in:
Emmanuel BENOîT 2017-11-12 22:20:11 +01:00
parent bf1c4aa1b0
commit 6c58e8669f
4 changed files with 99 additions and 27 deletions

View file

@ -12,7 +12,9 @@ enum E_OpType
// //
OP_CALL , OP_CALL ,
OP_RET , OP_RET ,
OP_COND_JUMP , //
OP_SKIP ,
OP_COND_SKIP ,
// //
OP_RES_STACK , OP_RES_STACK ,
OP_PUSH , OP_PUSH ,
@ -44,17 +46,30 @@ int32_t DeltaFPUStack( E_OpType op ) noexcept;
struct T_Op struct T_Op
{ {
static constexpr int MAX_ARGS = 4;
E_OpType op; E_OpType op;
T_SRDLocation location; T_SRDLocation location;
uint32_t arg0 , arg1; uint32_t args[ MAX_ARGS ];
T_Op( const E_OpType op , T_Op( const E_OpType op ,
T_SRDLocation const& location , T_SRDLocation const& location ,
const uint32_t arg0 = 0 , const uint32_t arg0 = 0 ) noexcept
const uint32_t arg1 = 0 ) noexcept
: op( op ) , location( location ) , : 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& ); M_LSHIFT_OP( T_StringBuilder , T_Op const& );

View file

@ -4,15 +4,14 @@
( (
(set vp-height $height) (set vp-height $height)
(set vp-width (mul $height (div 16 9))) (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-width $width)
(set vp-height (div $width (div 16 9))) (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") (program prg-fullscreen "fullscreen.v.glsl")

View file

@ -28,7 +28,31 @@ struct T_CompilerImpl_
fiSamplers , fiTextures; fiSamplers , fiTextures;
uint32_t sdMain , sdFPU; 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 gatherConstants( ) noexcept;
void countAssets( ) noexcept; void countAssets( ) noexcept;
@ -54,7 +78,7 @@ struct T_CompilerImpl_
T_SRDLocation const& location ) noexcept; T_SRDLocation const& location ) noexcept;
void addInstruction( void addInstruction(
E_OpType op , E_OpType op ,
uint32_t arg0 , uint32_t arg1 , std::initializer_list< uint32_t > args ,
T_SRDLocation const& location ) noexcept; T_SRDLocation const& location ) noexcept;
void applyStackEffects( void applyStackEffects(
T_Op const& op ) noexcept; T_Op const& op ) noexcept;
@ -347,8 +371,20 @@ bool T_CompilerImpl_::compileNode(
case A_Node::OP_COND: case A_Node::OP_COND:
if ( exit ) { 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( ) ); addInstruction( OP_POP , 0 , node.location( ) );
sdMain --; sdMain --;
condJumps.removeLast( );
} else {
condJumps.addNew( );
} }
break; break;
@ -361,21 +397,46 @@ bool T_CompilerImpl_::compileNode(
case A_Node::TN_CASE: case A_Node::TN_CASE:
if ( exit ) { 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 cpos( output->ops.sizeOf( funcIndex ) );
const auto diff( cpos - condJumps.last( ) ); const auto ppos( condJumps.last( ).prevCase );
output->ops.get( funcIndex , condJumps.last( ) ).arg1 = diff - 1; const auto diff( cpos - ppos );
condJumps.removeLast( ); assert( diff > 1 );
output->ops.get( funcIndex , ppos ).args[ 1 ] = diff - 1;
#ifdef INVASIVE_TRACES #ifdef INVASIVE_TRACES
printf( "\tCOND JUMP UPDATED: %d\n" , diff - 1 ); printf( "\tCOND JUMP UPDATED: %d\n" , diff - 1 );
#endif #endif
} else { } 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 ); auto& c( (T_CondInstrNode::T_ValuedCase&) node );
condJumps.add( output->ops.sizeOf( funcIndex ) ); condJumps.last( ).prevCase = output->ops.sizeOf( funcIndex );
addInstruction( OP_COND_JUMP , 0 , c.value( ) , addInstruction( OP_COND_SKIP , { 0 , uint32_t( c.value( ) ) } ,
node.location( ) ); node.location( ) );
} }
break; 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_EQ: case A_Node::EXPR_CMP_NE:
case A_Node::EXPR_CMP_GT: case A_Node::EXPR_CMP_GE: case A_Node::EXPR_CMP_GT: case A_Node::EXPR_CMP_GE:
case A_Node::EXPR_CMP_LT: case A_Node::EXPR_CMP_LE: case A_Node::EXPR_CMP_LT: case A_Node::EXPR_CMP_LE:
@ -520,12 +581,11 @@ void T_CompilerImpl_::addInstruction(
void T_CompilerImpl_::addInstruction( void T_CompilerImpl_::addInstruction(
const E_OpType op , const E_OpType op ,
const uint32_t arg0 , std::initializer_list< uint32_t > args ,
const uint32_t arg1 ,
T_SRDLocation const& location ) noexcept T_SRDLocation const& location ) noexcept
{ {
assert( ArgumentsFor( op ) == 2 ); assert( ArgumentsFor( op ) == args.size( ) );
applyStackEffects( output->ops.addNew( op , location , arg0 , arg1 ) ); applyStackEffects( output->ops.addNew( op , location , args ) );
} }
void T_CompilerImpl_::applyStackEffects( void T_CompilerImpl_::applyStackEffects(

12
ops.cc
View file

@ -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_CALL , T_OpInfo{ "call" , 1 } );
infos.add( E_OpType::OP_RET , T_OpInfo{ "ret" , 1 , OpStackMain{ -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_RES_STACK , T_OpInfo{ "res-stack" , 1 } );
infos.add( E_OpType::OP_PUSH , T_OpInfo{ "push" , 0 , OpStackMain{ 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 ) T_Op const& op )
{ {
sb << op.op; sb << op.op;
const auto args{ OpInfoTable_.get( op.op )->nArgs }; const auto args{ OpInfoTable_.get( op.op )->nArgs };
if ( args ) { for ( auto i = 0u ; i < args ; i ++ ) {
sb << ' ' << op.arg0; sb << ' ' << op.args[ i ];
if ( args == 2 ) {
sb << ' ' << op.arg1;
}
} }
return sb; return sb;
} }