demotool/m-builder.cc
Emmanuel BENOîT 94b01e62b4 Optimizer - Started work on function inlining
For now:
* Option that triggers inlining
* Compute list of inline-able functions
2017-12-17 15:59:29 +01:00

276 lines
6.5 KiB
C++

#include "externals.hh"
#include "c-opast.hh"
#include "c-ops.hh"
#include "c-opcomp.hh"
#include "c-opopt.hh"
#include <getopt.h>
#include <ebcl/Files.hh>
#include <ebcl/SRDText.hh>
#include <ebcl/Algorithms.hh>
using namespace ebcl;
using namespace opast;
#define M_LOGSTR( S , L ) \
logger( [](){ return T_StringBuilder{ S }; } , L )
namespace {
const struct option CmdLineOpts_[] = {
{ "log-level" , required_argument , 0 , 'L' } ,
{ "source-path" , required_argument , 0 , 's' } ,
{ "config" , required_argument , 0 , 'c' } ,
{ 0 , 0 , 0 , 0 }
};
/*============================================================================*/
void PrintStreamError(
char const* const prefix ,
T_String const& name ,
X_StreamError const& error ) noexcept
{
T_StringBuilder sb;
sb << prefix << " '" << name << "': " << error.what( );
if ( error.code( ) == E_StreamError::SYSTEM_ERROR ) {
sb << " (error code " << error.systemError( ) << ")";
}
sb << '\n' << '\0';
fprintf( stderr , "%s" , sb.data( ) );
}
void WriteSRDError(
T_StringBuilder& sb ,
T_SRDError const& error ) noexcept
{
switch ( error.type( ) ) {
case E_SRDErrorType::ERROR:
sb << "[ERROR";
break;
case E_SRDErrorType::WARNING:
sb << " [WARN";
break;
case E_SRDErrorType::NOTE:
sb << " [NOTE";
break;
}
sb << '(' << error.location( ) << ")] " << error.error( ) << '\n';
}
void WriteSRDErrors(
char const* const title ,
T_SRDErrors 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( ) );
}
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
{
T_StringBuilder sb;
if ( path ) {
sb << path;
if ( !path.endsWith( "/" ) ) {
sb << '/';
}
}
sb << name;
return T_String{ std::move( sb ) };
}
/*============================================================================*/
} // namespace
int main( int argc , char** argv )
{
// Parse command line
T_Optional< uint32_t > oLogLevel;
T_String oSrcPath;
T_String oBuildCfg;
int c;
while ( ( c = getopt_long( argc , argv , "L:s:c:" , CmdLineOpts_ , nullptr ) ) != -1 ) {
switch ( c ) {
case 'L':
oLogLevel = uint32_t( atoi( optarg ) );
break;
case 's':
if ( oSrcPath ) {
fprintf( stderr , "Duplicate source path\n" );
return EXIT_FAILURE;
}
oSrcPath = optarg;
break;
case 'c':
if ( oBuildCfg ) {
fprintf( stderr , "Duplicate build configuration\n" );
return EXIT_FAILURE;
}
oBuildCfg = optarg;
break;
}
}
// Logger setup
const uint32_t logLevel{ oLogLevel ? *oLogLevel : 0 };
const auto logger{ [=]( F_OPGenLog func , uint32_t level ) {
if ( level > logLevel ) {
return;
}
auto sb{ func( ) };
sb << '\0';
printf( "(%d) %s\n" , level , sb.data( ) );
} };
// Build configurations
M_LOGSTR( "Loading build configurations" , 1 );
const T_String bcfgFile{ FilePath( oSrcPath , "build.srd" ) };
const T_BuildConfiguration cfg{ [&]() {
try {
T_BuildConfigurationLoader bcfgLoader;
T_BuildConfigurations cfs{ bcfgLoader.load( bcfgFile ) };
if ( oBuildCfg && !cfs.contains( oBuildCfg ) ) {
fprintf( stderr , "===== BUILD CONFIGURATIONS\n" );
fprintf( stderr , "Build configuration not found\n" );
exit( EXIT_FAILURE );
}
if ( oBuildCfg ) {
return *cfs.get( oBuildCfg );
}
if ( cfs.size( ) ) {
return cfs[ 0 ];
}
return T_BuildConfiguration{ };
} catch ( X_StreamError const& e ) {
fprintf( stderr , "===== BUILD CONFIGURATIONS\n" );
PrintStreamError( "Could not open" , bcfgFile , e );
exit( EXIT_FAILURE );
} catch ( X_SRDErrors const& e ) {
WriteSRDErrors( "BUILD CONFIGURATIONS" , e.errors );
exit( EXIT_FAILURE );
}
} () };
// Load curves
M_LOGSTR( "Loading curves data" , 1 );
const T_String curvesFile{ FilePath( oSrcPath , "curves.srd" ) };
T_SyncCurvesIO::T_Data p;
try {
p = T_SyncCurvesIO{}.load( curvesFile );
} catch ( ebcl::X_StreamError const& e ) {
fprintf( stderr , "===== CURVES DATA\n" );
PrintStreamError( "Could not open" , curvesFile , e );
exit( EXIT_FAILURE );
} catch ( ebcl::X_SRDErrors const& e ) {
WriteSRDErrors( "CURVES DATA" , e.errors );
exit( EXIT_FAILURE );
}
// Open and load script
M_LOGSTR( "Loading script" , 1 );
const T_String inputName{ FilePath( oSrcPath , "demo.srd" ) };
T_SRDMemoryTarget srdOut;
{
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 script
M_LOGSTR( "Parsing script" , 1 );
T_OpsParser parser;
parser.setLogger( logger );
if ( !parser.parse( srdOut.list( ) ) ) {
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 ) {
od.fixedSize = cfg.resolutions[ 0 ]; // FIXME
}
if ( cfg.cfInputs ) {
od.curves = &p.curves;
}
bool didStuff;
do {
didStuff = false;
if ( cfg.constantFolding && opopt::FoldConstants( *parsed , od ) ) {
didStuff = true;
}
if ( cfg.constantPropagation && opopt::PropagateConstants( *parsed , od ) ) {
didStuff = true;
}
if ( cfg.deadCodeElimination && opopt::RemoveDeadCode( *parsed , od ) ) {
didStuff = true;
}
if ( cfg.inlineFunctions && opopt::InlineFunctions( *parsed , od ) ) {
didStuff = true;
}
} while ( didStuff );
}
// Compile
M_LOGSTR( "Compiling script" , 1 );
T_OpsCompiler compiler( true );
compiler.setLogger( logger );
compiler.compile( *parsed );
return 0;
}