Builder tool - Logging

Added logging using F_OPLogger wherever there were traces.
This commit is contained in:
Emmanuel BENOîT 2017-12-03 13:05:54 +01:00
parent da0d419fab
commit c4ce6e90d7
5 changed files with 210 additions and 146 deletions

View file

@ -3,19 +3,26 @@
#include "c-opcomp.hh"
#include <ebcl/Algorithms.hh>
//#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(

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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( ) );

View file

@ -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;
}