Compiler - Conditionals
This commit is contained in:
parent
bf1c4aa1b0
commit
6c58e8669f
4 changed files with 99 additions and 27 deletions
25
control.hh
25
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& );
|
||||
|
||||
|
|
7
demo.srd
7
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")
|
||||
|
||||
|
|
82
opcomp.cc
82
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(
|
||||
|
|
12
ops.cc
12
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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue