diff --git a/c-buildcfg.cc b/c-buildcfg.cc index dd0d4c1..93a2572 100644 --- a/c-buildcfg.cc +++ b/c-buildcfg.cc @@ -79,6 +79,22 @@ bool BCLResolutions_( T_SRDParserData const& data ) /*----------------------------------------------------------------------------*/ +F_SRDHandler BCLToggle_( + ptrdiff_t const fldOffset ) noexcept +{ + return [=]( T_SRDParserData const& d ) -> bool { + auto const& in{ *d.input }; + char* bCfg{ (char*) &d.currentData->value< T_BuildConfiguration >( ) }; + *(bool*)( bCfg + fldOffset ) = ( in[ 1 ].stringValue( ) == "on" ); + return true; + }; +} + +#define M_BCL_TOGGLE_( N ) \ + BCLToggle_( offsetof( T_BuildConfiguration , N ) ) + +/*----------------------------------------------------------------------------*/ + T_SRDParserConfig BCLInitDefinitions_( ) noexcept { using namespace ebcl::SRD; @@ -116,40 +132,20 @@ T_SRDParserConfig BCLInitDefinitions_( ) noexcept defs.context( "optim" ) << ( Rule( ) << "constant-folding" << "off" - << []( T_SRDParserData const& d ) -> bool { - auto& bCfg{ d.currentData->value< T_BuildConfiguration >( ) }; - bCfg.constantFolding = false; - return true; - } ) + << M_BCL_TOGGLE_( constantFolding ) ) << ( Rule( ) << "constant-folding" << "on" << EnterContext( "opt-cf" ) - << []( T_SRDParserData const& d ) -> bool { - auto& bCfg{ d.currentData->value< T_BuildConfiguration >( ) }; - bCfg.constantFolding = true; - return true; - } ) + << M_BCL_TOGGLE_( constantFolding ) ) + << ( Rule( ) << "constant-propagation" << Enum( "on-off" ) + << M_BCL_TOGGLE_( constantPropagation ) ) << ( Rule( ) << "dead-code-elimination" << Enum( "on-off" ) - << []( T_SRDParserData const& d ) -> bool { - auto& bCfg{ d.currentData->value< T_BuildConfiguration >( ) }; - bCfg.deadCodeElimination = true; - return true; - } ) + << M_BCL_TOGGLE_( deadCodeElimination ) ) ; defs.context( "opt-cf" ) << ( Rule( ) << "fixed-resolution" << Enum( "on-off" ) - << []( T_SRDParserData const& d ) -> bool { - auto const& in{ *d.input }; - auto& bCfg{ d.currentData->value< T_BuildConfiguration >( ) }; - bCfg.cfFixedSize = ( in[ 1 ].stringValue( ) == "on" ); - return true; - } ) + << M_BCL_TOGGLE_( cfFixedSize ) ) << ( Rule( ) << "inputs" << Enum( "on-off" ) - << []( T_SRDParserData const& d ) -> bool { - auto const& in{ *d.input }; - auto& bCfg{ d.currentData->value< T_BuildConfiguration >( ) }; - bCfg.cfInputs = ( in[ 1 ].stringValue( ) == "on" ); - return true; - } ) + << M_BCL_TOGGLE_( cfInputs ) ) ; return T_SRDParserConfig{ defs }; diff --git a/c-buildcfg.hh b/c-buildcfg.hh index aa908e4..a6ca6aa 100644 --- a/c-buildcfg.hh +++ b/c-buildcfg.hh @@ -27,6 +27,10 @@ struct T_BuildConfiguration // Get rid of (get-input) for constant or undefined curves bool cfInputs{ false }; + // Constant propagation ------------------------------------------------ + + bool constantPropagation{ false }; + // Dead code elimination ----------------------------------------------- bool deadCodeElimination{ false }; diff --git a/c-opcomp.cc b/c-opcomp.cc index afd9523..4a5ba16 100644 --- a/c-opcomp.cc +++ b/c-opcomp.cc @@ -16,13 +16,17 @@ namespace { struct T_CompilerImpl_ { - T_CompilerImpl_( F_OPLogger* logger ) noexcept - : logger( *logger ) {} + T_CompilerImpl_( F_OPLogger* const logger , + const bool noUIInstructions ) noexcept + : logger( *logger ) , noUIInstructions( noUIInstructions ) + {} P_OpProgram compile( T_OpsParserOutput const& input ) noexcept; private: F_OPLogger& logger; + const bool noUIInstructions; + T_Visitor< A_Node > astVisitor{ ASTVisitorBrowser }; T_Set< uint32_t > constants{ UseTag< IndexBacked< > >( ) }; T_KeyValueTable< T_String , uint32_t > locations; @@ -650,6 +654,9 @@ bool T_CompilerImpl_::compileNode( //- DEBUGGING / UI CONTROLS ----------------------------------------------------------- case A_Node::OP_PROFILE: + if ( noUIInstructions ) { + break; + } if ( exit ) { addInstruction( OP_UI_PEXIT , node.location( ) ); } else { @@ -663,6 +670,9 @@ bool T_CompilerImpl_::compileNode( break; case A_Node::OP_INPUT: + if ( noUIInstructions ) { + break; + } if ( exit ) { auto& in( (T_InputInstrNode&) node ); T_OpValue value; @@ -675,6 +685,9 @@ bool T_CompilerImpl_::compileNode( break; case A_Node::OP_ODBG: + if ( noUIInstructions ) { + break; + } if ( exit ) { auto& n( (T_OutputDebugInstrNode&) node ); if ( ! output->uiStrings.contains( n.description( ) ) ) { @@ -689,6 +702,9 @@ bool T_CompilerImpl_::compileNode( break; case A_Node::OP_OVERRIDES: + if ( noUIInstructions ) { + break; + } if ( exit ) { auto& n{ (T_OverridesInstrNode&) node }; const auto idx{ output->overrides.add( n.extractRoot( ) ) }; @@ -917,8 +933,9 @@ void T_CompilerImpl_::applyStackEffects( /*= T_OpsCompiler ==============================================================*/ -T_OpsCompiler::T_OpsCompiler( ) noexcept - : A_PrivateImplementation( new T_CompilerImpl_( &logger_ ) ) +T_OpsCompiler::T_OpsCompiler( + const bool noUIInstructions ) noexcept + : A_PrivateImplementation( new T_CompilerImpl_( &logger_ , noUIInstructions ) ) { } P_OpProgram T_OpsCompiler::compile( diff --git a/c-opcomp.hh b/c-opcomp.hh index 4a5afa7..85ddb96 100644 --- a/c-opcomp.hh +++ b/c-opcomp.hh @@ -57,7 +57,7 @@ class T_OpsCompiler : public ebcl::A_PrivateImplementation F_OPLogger logger_{ []( auto , auto ) { } }; public: - T_OpsCompiler( ) noexcept; + T_OpsCompiler( bool noUIInstructions = false ) noexcept; void setLogger( F_OPLogger logger ) { diff --git a/c-opopt.cc b/c-opopt.cc index ee45246..bb8ef11 100644 --- a/c-opopt.cc +++ b/c-opopt.cc @@ -392,6 +392,27 @@ bool opopt::FoldConstants( } +/*= CONSTANT PROPAGATION =====================================================*/ + +bool opopt::PropagateConstants( + T_OpsParserOutput& program , + T_OptData& optData ) noexcept +{ + // We need to follow the general execution flow of the program. This is + // not as straightforward as it seems. + // - Handling locals is rather easy as they "die" at the end of + // the function in which they are defined. + // - Handling variables in init and functions that are called only + // from init is not too hard: once a variable is set to a constant, it + // can be substituted until the next set instruction. + // - Other variables need additional checks before propagating. + // For example, if a variable is set to a constant during init, but is + // updated at the end of the frame function, the value cannot be + // propagated. + return false; +} + + /*= DEAD CODE REMOVAL ========================================================*/ bool opopt::RemoveDeadCode( diff --git a/c-opopt.hh b/c-opopt.hh index ccd749a..695d337 100644 --- a/c-opopt.hh +++ b/c-opopt.hh @@ -39,18 +39,28 @@ struct T_OptData void findInputDecls( T_OpsParserOutput& program ) noexcept; }; -/*----------------------------------------------------------------------------*/ -// Attempts to fold constant expressions into single constants. Returns true if -// transformations were made, false if not. +/*= INDIVIDUAL OPTIMISATIONS =================================================*/ +// All functions below return true if transformations were made, false if not. + +// Attempts to fold constant expressions into single constants. // -bool FoldConstants( T_OpsParserOutput& program , +bool FoldConstants( + T_OpsParserOutput& program , + T_OptData& optData ) noexcept; + +// Attempts to propagate values from variables that contain constants to the +// locations at which they are used. +// +bool PropagateConstants( + T_OpsParserOutput& program , T_OptData& optData ) noexcept; // Attempt to remove blocks of code that will not be executed because of -// constant conditions. Returns true if transformations were made, false if not. +// constant conditions. // -bool RemoveDeadCode( T_OpsParserOutput& program , +bool RemoveDeadCode( + T_OpsParserOutput& program , T_OptData& optData ) noexcept; diff --git a/m-builder.cc b/m-builder.cc index 6601caa..d5a98d3 100644 --- a/m-builder.cc +++ b/m-builder.cc @@ -132,7 +132,7 @@ int main( int argc , char** argv ) break; case 'c': - if ( oSrcPath ) { + if ( oBuildCfg ) { fprintf( stderr , "Duplicate build configuration\n" ); return EXIT_FAILURE; } @@ -252,22 +252,18 @@ int main( int argc , char** argv ) bool doneStuff; do { doneStuff = false; - if ( cfg.constantFolding ) { - while ( opopt::FoldConstants( *parsed , od ) ) { - doneStuff = true; - } + if ( cfg.constantFolding && opopt::FoldConstants( *parsed , od ) ) { + doneStuff = true; } - if ( cfg.deadCodeElimination ) { - while ( opopt::RemoveDeadCode( *parsed , od ) ) { - doneStuff = true; - } + if ( cfg.deadCodeElimination && opopt::RemoveDeadCode( *parsed , od ) ) { + doneStuff = true; } } while ( doneStuff ); } // Compile M_LOGSTR( "Compiling script" , 1 ); - T_OpsCompiler compiler; + T_OpsCompiler compiler( true ); compiler.setLogger( logger ); compiler.compile( *parsed ); return 0; diff --git a/test/build.srd b/test/build.srd index 48fd338..c2c68ca 100644 --- a/test/build.srd +++ b/test/build.srd @@ -1,4 +1,4 @@ -(cfg "Default" +(cfg "Optimized" (resolutions (1280 720) (1920 1080) @@ -7,3 +7,11 @@ (constant-folding on) ) ) + +(cfg "Basic" + (resolutions + (1280 720) + (1920 1080) + ) + (optimizer off) +) diff --git a/test/curves.srd b/test/curves.srd index 4eff85b..a18440f 100644 --- a/test/curves.srd +++ b/test/curves.srd @@ -1,7 +1,7 @@ (duration 0.133333 450) (camera-nearplane - (segment linear + (segment smooth (values 1.1547 1.1547 4.82843) (durations 225 225) ) @@ -9,7 +9,7 @@ (camera-pos-x (segment linear - (values -300 -150 0) + (values -4000 -2000 0) (durations 225 225) ) ) @@ -51,7 +51,7 @@ (camera-lookat-x (segment linear - (values -300 -150 0) + (values -4000 -2000 0) (durations 225 225) ) )