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_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& );
|
||||||
|
|
||||||
|
|
7
demo.srd
7
demo.srd
|
@ -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")
|
||||||
|
|
||||||
|
|
82
opcomp.cc
82
opcomp.cc
|
@ -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
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_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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue