diff --git a/c-opcomp.cc b/c-opcomp.cc index 6000455..afd9523 100644 --- a/c-opcomp.cc +++ b/c-opcomp.cc @@ -3,19 +3,26 @@ #include "c-opcomp.hh" #include -//#define INVASIVE_TRACES - using namespace ebcl; using namespace ops; using namespace opast; + +#define M_LOGSTR_( S , L ) \ + logger( [](){ return T_StringBuilder{ S }; } , L ) + + namespace { struct T_CompilerImpl_ { + T_CompilerImpl_( F_OPLogger* logger ) noexcept + : logger( *logger ) {} + P_OpProgram compile( T_OpsParserOutput const& input ) noexcept; private: + F_OPLogger& logger; T_Visitor< A_Node > astVisitor{ ASTVisitorBrowser }; T_Set< uint32_t > constants{ UseTag< IndexBacked< > >( ) }; T_KeyValueTable< T_String , uint32_t > locations; @@ -107,53 +114,66 @@ P_OpProgram T_CompilerImpl_::compile( // and frame is always 1 output->init = input->root.functionIndex( "*init*" ); output->frame = input->root.functionIndex( "*frame*" ); -#ifdef INVASIVE_TRACES - printf( "function indices\n\t%d\tinit\n\t%d\tframe\n" , - output->init , output->frame ); -#endif + logger( [this]( ) { + T_StringBuilder sb; + sb << "Function indices\n\tinit: " << output->init + << "\n\tframe: " << output->frame; + return sb; + } , 3 ); // Compile each function -#ifdef INVASIVE_TRACES uint32_t nInstr = 0; -#endif uint32_t cfi; for ( cfi = 0u ; cfi < input->root.nFunctions( ) ; cfi ++ ) { output->ops.next( ); auto& func( input->root.function( cfi ) ); -#ifdef INVASIVE_TRACES - printf( "compiling function %s\n" , - func.name( ).toOSString( ).data( ) ); -#endif + logger( [&]( ) { + T_StringBuilder sb; + sb << "... Compiling function " << func.name( ); + return sb; + } , 3 ); + sdMain = sdFPU = 0; astVisitor.visit( func , [=]( A_Node& node , const bool exit ) -> bool { return compileNode( cfi , node , exit ); } ); -#ifdef INVASIVE_TRACES - T_StringBuilder dump , temp; - for ( auto i = 0u ; i < output->ops.sizeOf( cfi ) ; i ++ ) { - temp << "(" << output->ops.get( cfi , i ) << ")"; - while ( temp.length( ) < 30 ) { - temp << ' '; + + logger( [&]( ) { + T_StringBuilder sb , temp; + sb << "...... Compiled function " << func.name( ); + for ( auto i = 0u ; i < output->ops.sizeOf( cfi ) ; i ++ ) { + temp << "(" << output->ops.get( cfi , i ) << ")"; + while ( temp.length( ) < 30 ) { + temp << ' '; + } + sb << "\n\t\t" << temp << "{ " + << output->ops.get( cfi , i ).location + << " }"; + temp.clear( ); } - dump << "\t\t" << temp << "{ " << output->ops.get( cfi , i ).location << " }\n"; - temp.clear( ); - } - dump << '\t' << output->ops.sizeOf( cfi ) << " instructions\n" - << '\0'; - printf( "%s" , dump.data( ) ); + return sb; + } , 4 ); + logger( [&]( ) { + T_StringBuilder sb; + sb << "...... " << output->ops.sizeOf( cfi ) + << " instructions"; + return sb; + } , 3 ); nInstr += output->ops.sizeOf( cfi ); -#endif } -#ifdef INVASIVE_TRACES - printf( "total %d instructions\n" , nInstr ); -#endif + logger( [=]( ) { + T_StringBuilder sb; + sb << "... Generated " << nInstr << " instructions"; + return sb; + } , 2 ); return std::move( output ); } void T_CompilerImpl_::gatherConstants( ) noexcept { + M_LOGSTR_( "... Gathering constants" , 2 ); constants.clear( ); astVisitor.visit( input->root , [&]( A_Node& node , const bool exit ) { if ( exit ) { @@ -175,22 +195,24 @@ void T_CompilerImpl_::gatherConstants( ) noexcept output->constants.add( constants[ i ] ); } -#ifdef INVASIVE_TRACES - printf( "%d constants\n" , constants.size( ) ); - for ( auto i = 0u ; i < constants.size( ) ; i ++ ) { - printf( " %08x" , constants[ i ] ); - if ( i % 4 == 3 ) { - printf( "\n" ); + logger( [&]() { + T_StringBuilder sb; + char temp[ 9 ]; + sb << constants.size( ) << " constants\n\t"; + for ( auto i = 0u ; i < constants.size( ) ; i ++ ) { + snprintf( temp , 9 , "%08x" , constants[ i ] ); + sb << " " << temp; + if ( i % 4 == 3 && i != constants.size( ) - 1 ) { + sb << "\n\t"; + } } - } - if ( constants.size( ) % 4 ) { - printf( "\n" ); - } -#endif + return sb; + } , 3 ); } void T_CompilerImpl_::countAssets( ) noexcept { + M_LOGSTR_( "... Counting resources" , 2 ); locations.clear( ); locations.add( T_String::Pooled( "time" ) , 0u ); locations.add( T_String::Pooled( "width" ) , 1u ); @@ -268,47 +290,46 @@ void T_CompilerImpl_::countAssets( ) noexcept } } -#ifdef INVASIVE_TRACES - printf( "assets\n\t%d framebuffers\n\t%d pipelines\n" - "\t%d programs\n\t%d samplers\n\t%d textures\n" - "\t%d variables\n\t%d inputs\n" , - output->nFramebuffers , output->nPipelines , - output->nPrograms , output->nSamplers , - output->nTextures , output->nVariables , - output->inputs.size( ) ); - printf( "table ranges\n\t0\t2\tBuilt-ins\n" - "\t3\t%d\tConstants\n" - "\t%d\t%d\tVariables\n" - "\t%d\t%d\tFramebuffers\n" - "\t%d\t%d\tPipelines\n" - "\t%d\t%d\tPrograms\n" - "\t%d\t%d\tSamplers\n" - "\t%d\t%d\tTextures\n" , - fiVariables - 1 , fiVariables , fiFramebuffers - 1 , fiFramebuffers , - fiPipelines - 1 , fiPipelines , fiPrograms - 1 , fiPrograms , - fiSamplers - 1 , fiSamplers , fiTextures - 1 , fiTextures , - fiTextures + output->nTextures - 1 ); - - T_Array< uint32_t > indices( locations.size( ) ); - indices.ensureCapacity( locations.size( ) ); - for ( auto i = 0u ; i < locations.size( ) ; i ++ ) { - indices.add( i ); - } - indices.sort( [this]( uint32_t a , uint32_t b ) { - return T_Comparator< uint32_t >::compare( - locations.values( )[ a ] , - locations.values( )[ b ] ); - } ); - T_StringBuilder lmap; - lmap << "location map (constants not included)\n"; - for ( auto idx : indices ) { - lmap << '\t' << locations.values( )[ idx ] - << '\t' << locations.keys( )[ idx ] - << '\n'; - } - lmap << '\0'; - printf( "%s" , lmap.data( ) ); -#endif + logger( [&]() { + T_StringBuilder sb; + sb << "... Resource counts:\n" + << "\t\tFramebuffers:\t" << output->nFramebuffers << '\n' + << "\t\tPipelines: \t" << output->nPipelines << '\n' + << "\t\tPrograms: \t" << output->nPrograms << '\n' + << "\t\tSamplers: \t" << output->nSamplers << '\n' + << "\t\tTextures: \t" << output->nTextures << '\n' + << "\t\tInputs: \t" << output->inputs.size( ) << '\n' + << "\tTable ranges:\n" + << "\t\tBuilt-ins \t0\t2\n" + << "\t\tConstants \t3\t" << fiVariables - 1 << '\n' + << "\t\tVariables \t" << fiVariables << '\t' << fiFramebuffers - 1 << '\n' + << "\t\tFramebuffers \t" << fiFramebuffers << '\t' << fiPipelines - 1 << '\n' + << "\t\tPipelines \t" << fiPipelines << '\t' << fiPrograms - 1 << '\n' + << "\t\tPrograms \t" << fiPrograms << '\t' << fiSamplers - 1 << '\n' + << "\t\tSamplers \t" << fiSamplers << '\t' << fiTextures - 1 << '\n' + << "\t\tTextures \t" << fiTextures << '\t' << fiTextures + output->nTextures - 1 + ; + return sb; + } , 3 ); + logger( [&]() { + T_StringBuilder sb; + T_Array< uint32_t > indices( locations.size( ) ); + indices.ensureCapacity( locations.size( ) ); + for ( auto i = 0u ; i < locations.size( ) ; i ++ ) { + indices.add( i ); + } + indices.sort( [this]( uint32_t a , uint32_t b ) { + return T_Comparator< uint32_t >::compare( + locations.values( )[ a ] , + locations.values( )[ b ] ); + } ); + sb << "... Location map (constants not included)"; + for ( auto idx : indices ) { + sb << "\n\t" << locations.values( )[ idx ] + << '\t' << locations.keys( )[ idx ]; + } + return sb; + } , 4 ); } bool T_CompilerImpl_::compileNode( @@ -873,12 +894,12 @@ void T_CompilerImpl_::applyStackEffects( const auto m( DeltaMainStack( op.op ) ); const auto f( DeltaFPUStack( op.op ) ); -#ifdef INVASIVE_TRACES - T_StringBuilder sb; - sb << "applying stack effects for (" << op << ") - sdMain " << sdMain - << " (" << m << ") sdFPU " << sdFPU << " (" << f << ")" << '\n' << '\0'; - printf( "%s" , sb.data( ) ); -#endif + logger( [&]() { + T_StringBuilder sb; + sb << "applying stack effects for (" << op << ") - sdMain " << sdMain + << " (" << m << ") sdFPU " << sdFPU << " (" << f << ')'; + return sb; + } , 5 ); if ( m ) { assert( m > 0 || sdMain >= uint32_t( -m ) ); @@ -897,7 +918,7 @@ void T_CompilerImpl_::applyStackEffects( /*= T_OpsCompiler ==============================================================*/ T_OpsCompiler::T_OpsCompiler( ) noexcept - : A_PrivateImplementation( new T_CompilerImpl_( ) ) + : A_PrivateImplementation( new T_CompilerImpl_( &logger_ ) ) { } P_OpProgram T_OpsCompiler::compile( diff --git a/c-opcomp.hh b/c-opcomp.hh index bf36a81..4a5afa7 100644 --- a/c-opcomp.hh +++ b/c-opcomp.hh @@ -53,9 +53,21 @@ namespace ops { struct T_OpProgram; using P_OpProgram = T_OwnPtr< T_OpProgram >; // Generates bytecode based on the type-checked tree produced by the parser class T_OpsCompiler : public ebcl::A_PrivateImplementation { + private: + F_OPLogger logger_{ []( auto , auto ) { } }; + public: T_OpsCompiler( ) noexcept; + void setLogger( F_OPLogger logger ) + { + if ( logger ) { + logger_ = std::move( logger ); + } else { + logger_ = []( auto , auto ) { }; + } + } + ops::P_OpProgram compile( T_OpsParserOutput const& input ) noexcept; }; diff --git a/c-opopt.cc b/c-opopt.cc index f030bbe..ee45246 100644 --- a/c-opopt.cc +++ b/c-opopt.cc @@ -9,6 +9,10 @@ using namespace opast; using namespace opopt; +#define M_LOGSTR_( S , L ) \ + oData.logger( [](){ return T_StringBuilder{ S }; } , L ) + + /*= T_OptData ================================================================*/ void T_OptData::findInputDecls( @@ -140,7 +144,7 @@ template< T_StringBuilder sb; sb << "substituting node at " << child.location( ); return sb; - } , 2 ); + } , 3 ); r->location( ) = node.location( ); set( node , std::move( r ) ); didFold = true; @@ -235,17 +239,13 @@ P_ExpressionNode T_ConstantFolder_::doIdExpr( } if ( node.id( ) == "width" ) { - oData.logger( []{ - return T_StringBuilder{ "replacing $width with fixed width" }; - } , 2 ); + M_LOGSTR_( "replacing $width with fixed width" , 3 ); return NewOwned< T_ConstantExprNode >( node.parent( ) , double( oData.fixedSize->first ) ); } if ( node.id( ) == "height" ) { - oData.logger( []{ - return T_StringBuilder{ "replacing $height with fixed height" }; - } , 2 ); + M_LOGSTR_( "replacing $height with fixed height" , 3 ); return NewOwned< T_ConstantExprNode >( node.parent( ) , float( oData.fixedSize->second ) ); } @@ -374,9 +374,7 @@ bool opopt::FoldConstants( T_OptData& oData ) noexcept { T_ConstantFolder_ folder{ oData }; - oData.logger( []() { - return T_StringBuilder{ "constant folding pass" }; - } , 1 ); + M_LOGSTR_( "... Folding constants" , 2 ); if ( oData.curves ) { oData.findInputDecls( program ); } @@ -384,10 +382,12 @@ bool opopt::FoldConstants( return folder( n , x ); } ); oData.logger( [&]() { - return T_StringBuilder{ - folder.didFold ? "some constants were folded" - : "no constants were folded" }; - } , 1 ); + T_StringBuilder sb{ "...... " }; + sb << ( folder.didFold + ? "Some constants were folded" + : "No constants were folded" ); + return sb; + } , 2 ); return folder.didFold; } diff --git a/c-opparser.cc b/c-opparser.cc index 5255821..d5e79d6 100644 --- a/c-opparser.cc +++ b/c-opparser.cc @@ -12,6 +12,11 @@ using namespace ebcl; using namespace opast; +#define M_LOGSTR_( S , L ) \ + logger( [](){ return T_StringBuilder{ S }; } , L ) + + + /*= T_Parser =================================================================*/ namespace { @@ -308,7 +313,7 @@ inline T_ParserImpl_::T_ParserImpl_( T_Array< T_SRDError >* const errors , T_OwnPtr< T_OpsParserOutput >* const output , F_OPLogger* logger ) noexcept - : output( *output ) , errors( *errors ) , logger( *logger ) , + : output( *output ) , errors( *errors ) , logger{ *logger } , ovParserConfig( sov::GetParserConfig( ) ) , ovParser( ovParserConfig ) { } @@ -334,6 +339,7 @@ void T_ParserImpl_::main( bool T_ParserImpl_::checkRequiredBlocks( T_SRDList const& input ) noexcept { + M_LOGSTR_( "... Checking for required blocks" , 2 ); const T_SRDLocation missingErrLoc( ([&input]() { if ( input.size( ) != 0 ) { return T_SRDLocation( input[ 0 ].location( ).source( ) , 1 , 1 ); @@ -354,6 +360,7 @@ bool T_ParserImpl_::checkRequiredBlocks( */ bool T_ParserImpl_::checkCalls( ) noexcept { + M_LOGSTR_( "... Gathering/checking calls" , 2 ); calls.clear( ); uint32_t cfi; for ( cfi = 0 ; cfi < output->root.nFunctions( ) ; cfi ++ ) { @@ -399,6 +406,7 @@ bool T_ParserImpl_::checkCalls( ) noexcept */ bool T_ParserImpl_::checkInstructionRestrictions( ) noexcept { + M_LOGSTR_( "... Checking instruction restrictions" , 2 ); callInfo.clear( ); callInfo.resize( calls.size( ) ); @@ -449,6 +457,7 @@ bool T_ParserImpl_::checkInstructionRestrictions( ) noexcept */ bool T_ParserImpl_::checkLocalVariables( ) noexcept { + M_LOGSTR_( "... Checking local variables" , 2 ); uint32_t cfi; T_StringBuilder esb; for ( cfi = 0 ; cfi < output->root.nFunctions( ) ; cfi ++ ) { @@ -486,6 +495,8 @@ bool T_ParserImpl_::checkLocalVariables( ) noexcept */ bool T_ParserImpl_::collectGlobalTypes( ) noexcept { + M_LOGSTR_( "... Collecting global declaration types" , 2 ); + // Temporary table for type / first declaration location struct T_Decl_ { E_DataType type; @@ -538,7 +549,7 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept T_StringBuilder sb; sb << "id " << id << " as " << dt << " at " << location; return sb; - } , 2 ); + } , 3 ); // When we find a set instruction, we need to check whether // it is affecting a local variable. If it is we'll just skip @@ -589,7 +600,7 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept bool T_ParserImpl_::checkArgumentTypes( ) noexcept { - logger( []{ return T_StringBuilder{ "Checking argument types" }; } , 1 ); + M_LOGSTR_( "... Checking function argument types" , 2 ); // Find functions for which arguments types need to be resolved const auto nFunctions( output->root.nFunctions( ) ); @@ -629,12 +640,12 @@ bool T_ParserImpl_::checkArgumentTypes( ) noexcept } ); } -#define TRACE( x ) \ +#define M_TRACE_( l , x ) \ logger( [&]{ \ T_StringBuilder sb; \ sb << x; \ return sb; \ - } , 2 ) + } , l ) T_StringBuilder esb; bool changed = true; @@ -645,13 +656,13 @@ bool T_ParserImpl_::checkArgumentTypes( ) noexcept // resolved and check all calls. for ( auto i = 0u ; i < nFunctions ; i ++ ) { auto& f( output->root.function( i ) ); - TRACE( "about to check function " << f.name( ) ); + M_TRACE_( 3 , "about to check function " << f.name( ) ); if ( !argsResolved[ i ] ) { - TRACE( " -> arguments not resolved, skipped" ); + M_TRACE_( 3 , " -> arguments not resolved, skipped" ); continue; } - TRACE( " -> " << callInstuctions.sizeOf( i ) << " calls w/ arguments" ); + M_TRACE_( 3 , " -> " << callInstuctions.sizeOf( i ) << " calls w/ arguments" ); for ( auto c = 0u ; c < callInstuctions.sizeOf( i ) ; c ++ ) { auto const* call( callInstuctions.get( i , c ) ); if ( ! call ) { @@ -662,13 +673,13 @@ bool T_ParserImpl_::checkArgumentTypes( ) noexcept const auto calledIdx( output->root.functionIndex( called ) ); auto& calledFn( dynamic_cast< T_FuncNode& >( output->root.function( calledIdx ) ) ); - TRACE( " -> checking call to " << called << " (idx " << calledIdx + M_TRACE_( 4 , " -> checking call to " << called << " (idx " << calledIdx << ") at " << call->location( ) ); assert( call->arguments( ) == calledFn.arguments( ) ); if ( argsResolved[ calledIdx ] ) { - TRACE( " argument types already resolved, checking" ); + M_TRACE_( 4 , " argument types already resolved, checking" ); } else { - TRACE( " resolving arguments" ); + M_TRACE_( 4 , " resolving arguments" ); } bool ok = true; @@ -686,7 +697,7 @@ bool T_ParserImpl_::checkArgumentTypes( ) noexcept } else { ndt = E_DataType::VARIABLE; } - TRACE( " [" << a << "] " << ndt ); + M_TRACE_( 4 , " [" << a << "] " << ndt ); // Arguments not resolved -> try setting the argument's type if ( !argsResolved[ calledIdx ] ) { @@ -718,6 +729,8 @@ bool T_ParserImpl_::checkArgumentTypes( ) noexcept bool T_ParserImpl_::checkIdentifiers( ) noexcept { + M_LOGSTR_( "... Checking command argument types" , 2 ); + uint32_t cfi; T_StringBuilder esb; for ( cfi = 0 ; cfi < output->root.nFunctions( ) ; cfi ++ ) { @@ -914,6 +927,7 @@ E_DataType T_ParserImpl_::getTypeOf( bool T_ParserImpl_::parseTopLevel( T_SRDList const& input ) noexcept { + M_LOGSTR_( "... Generating tree" , 2 ); for ( auto const& t : input ) { if ( t.type( ) == E_SRDTokenType::LIST && t.list( ).size( ) > 0 ) { parseFunction( t.list( ) ); diff --git a/m-builder.cc b/m-builder.cc index af424c2..6601caa 100644 --- a/m-builder.cc +++ b/m-builder.cc @@ -14,6 +14,9 @@ using namespace ebcl; using namespace opast; +#define M_LOGSTR( S , L ) \ + logger( [](){ return T_StringBuilder{ S }; } , L ) + namespace { const struct option CmdLineOpts_[] = { @@ -72,6 +75,20 @@ void WriteSRDErrors( fprintf( stderr , "%s" , sb.data( ) ); } +void WriteSRDErrors( + char const* const title , + T_Array< T_SRDError > const& errors ) noexcept +{ + T_StringBuilder sb; + sb << "===== " << title << '\n'; + const auto nErrors( errors.size( ) ); + for ( auto i = 0u ; i < nErrors ; i ++ ) { + WriteSRDError( sb , errors[ i ] ); + } + sb << '\0'; + fprintf( stderr , "%s" , sb.data( ) ); +} + T_String FilePath( T_String const& path , char const* const name ) noexcept @@ -137,7 +154,7 @@ int main( int argc , char** argv ) } }; // Build configurations - logger( [](){ return T_StringBuilder{ "Loading build configurations" }; } , 1 ); + M_LOGSTR( "Loading build configurations" , 1 ); const T_String bcfgFile{ FilePath( oSrcPath , "build.srd" ) }; const T_BuildConfiguration cfg{ [&]() { try { @@ -167,18 +184,8 @@ int main( int argc , char** argv ) } } () }; - // Open file - const T_String inputName{ FilePath( oSrcPath , "demo.srd" ) }; - T_File input( inputName , E_FileMode::READ_ONLY ); - try { - input.open( ); - } catch ( X_StreamError const& e ) { - PrintStreamError( "Could not open" , inputName , e ); - return 1; - } - // Load curves - logger( [](){ return T_StringBuilder{ "Loading curves data" }; } , 1 ); + M_LOGSTR( "Loading curves data" , 1 ); const T_String curvesFile{ FilePath( oSrcPath , "curves.srd" ) }; T_SyncCurvesIO::T_Data p; try { @@ -193,38 +200,46 @@ int main( int argc , char** argv ) exit( EXIT_FAILURE ); } - // Load script + // Open and load script + M_LOGSTR( "Loading script" , 1 ); + const T_String inputName{ FilePath( oSrcPath , "demo.srd" ) }; T_SRDMemoryTarget srdOut; - srdOut.clearComments( true ).clearFlushToken( true ); - try { - T_SRDTextReader srdReader{ srdOut }; - T_FileInputStream fis{ input }; - srdReader.read( inputName , fis ); - } catch ( X_StreamError const& e ) { - fprintf( stderr , "===== SCRIPT\n" ); - PrintStreamError( "Could not open" , inputName , e ); - return 1; - } catch ( X_SRDErrors const& e ) { - WriteSRDErrors( "SCRIPT" , e.errors ); - exit( EXIT_FAILURE ); + { + T_File input( inputName , E_FileMode::READ_ONLY ); + try { + input.open( ); + } catch ( X_StreamError const& e ) { + PrintStreamError( "Could not open" , inputName , e ); + return 1; + } + srdOut.clearComments( true ).clearFlushToken( true ); + try { + T_SRDTextReader srdReader{ srdOut }; + T_FileInputStream fis{ input }; + srdReader.read( inputName , fis ); + } catch ( X_StreamError const& e ) { + fprintf( stderr , "===== SCRIPT\n" ); + PrintStreamError( "Could not open" , inputName , e ); + exit( EXIT_FAILURE ); + } catch ( X_SRDErrors const& e ) { + WriteSRDErrors( "SCRIPT" , e.errors ); + exit( EXIT_FAILURE ); + } } - // Parse + // Parse script + M_LOGSTR( "Parsing script" , 1 ); T_OpsParser parser; parser.setLogger( logger ); if ( !parser.parse( srdOut.list( ) ) ) { - T_StringBuilder sb; - for ( auto const& err : parser.errors( ) ) { - WriteSRDError( sb , err ); - } - sb << "Parser failed\n" << '\0'; - fprintf( stderr , "%s" , sb.data( ) ); - return 3; + WriteSRDErrors( "SCRIPT" , parser.errors( ) ); + exit( EXIT_FAILURE ); } auto parsed{ parser.result( ) }; // Optimize if ( cfg.optimize ) { + M_LOGSTR( "Optimizing script tree" , 1 ); opopt::T_OptData od; od.logger = logger; if ( !cfg.resolutionChooser && cfg.cfFixedSize ) { @@ -251,7 +266,9 @@ int main( int argc , char** argv ) } // Compile + M_LOGSTR( "Compiling script" , 1 ); T_OpsCompiler compiler; + compiler.setLogger( logger ); compiler.compile( *parsed ); return 0; }