Compiler - Started work

Committing as I need to make a few adjustments to the AST in order to
simplify things.
This commit is contained in:
Emmanuel BENOîT 2017-11-12 10:50:05 +01:00
parent 8806cd81d2
commit abb2c02d61
5 changed files with 307 additions and 33 deletions

View file

@ -31,6 +31,7 @@ COMMON = \
control.cc \
opast.cc \
opparser.cc \
opcomp.cc \
# END COMMON
DEMO = \

View file

@ -1,9 +1,114 @@
#pragma once
#ifndef REAL_BUILD
# include "externals.hh"
#endif
#include "sync.hh"
#include "opast.hh"
struct T_SyncData;
namespace ops {
using namespace ebcl;
enum E_OpType
{
OP_END ,
//
OP_FP_LOAD ,
//
OP_FP_CMP ,
};
struct T_Op
{
E_OpType op;
T_SRDLocation location;
uint32_t arg0 , arg1;
T_Op( const E_OpType op ,
T_SRDLocation const& location ,
const uint32_t arg0 = 0 ,
const uint32_t arg1 = 0 ) noexcept
: op( op ) , location( location ) ,
arg0( arg0 ) , arg1( arg1 )
{ }
};
union T_OpValue
{
int32_t i;
uint32_t u;
float f;
};
struct T_OpProgram
{
T_MultiArray< T_Op > ops; // All operations
uint32_t init , // Index of initialisation function
frame; // Index of frame rendering function
T_Array< T_OpValue > constants; // Constants values
uint32_t nVariables{ 0 }; // Amount of variables
T_Array< T_String > inputs; // Input definitions
uint32_t nPrograms{ 0 } , // Amount of programs
nFramebuffers{ 0 } , // Amount of framebuffers
nPipelines{ 0 } , // Amount of pipelines
nSamplers{ 0 } , // Amount of samplers
nTextures{ 0 }; // Amount of textures
T_Array< T_String > progNames; // GLSL program files
T_Array< T_String > uiStrings; // UI strings for profiling, etc.
};
using P_OpProgram = T_OwnPtr< T_OpProgram >;
struct T_OpContext
{
T_OpProgram& program; // The program
uint32_t instrPtr; // Instruction pointer
bool aborted; // Did the program fail?
T_Array< T_OpValue > values; // VM data
T_Array< T_OpValue > stack; // Main VM stack
double x87stack[ 8 ]; // x87 FPU emulation stack
int x87sp; // x87 FPU emulation stack pointer
};
class X_OpFailure : public std::exception
{
public:
X_OpFailure( ) = delete;
DEF_COPY( X_OpFailure );
DEF_MOVE( X_OpFailure );
X_OpFailure( T_Op const& op ,
T_String error ) noexcept;
T_Op const& op( ) const noexcept
{ return *op_; }
T_String const& error( ) const noexcept
{ return error_; }
char const* what( ) const noexcept override;
private:
T_Op const* op_;
T_String error_;
T_String fullMessage_;
};
class T_Compiler : public A_PrivateImplementation
{
public:
T_Compiler( ) noexcept;
P_OpProgram compile(
opast::T_ParserOutput const& input ) noexcept;
};
} // namespace ops
/*= FIXME OLD VERSION BELOW ====================================================*/
namespace cops {
@ -13,9 +118,6 @@ namespace cops {
{
T_Program const* program;
float const* time;
T_SyncData const* sync;
T_KeyValueTable< T_String , float > vars;
T_Array< float > opStack;

View file

@ -1211,7 +1211,6 @@ struct T_ParserOutput
{
T_RootNode root;
T_KeyValueTable< T_String , E_DataType > types;
T_Set< float > constants{ UseTag< IndexBacked< > >( ) };
};
// The actual parser

192
opcomp.cc Normal file
View file

@ -0,0 +1,192 @@
#include "externals.hh"
#include "control.hh"
#include <ebcl/Algorithms.hh>
#define INVASIVE_TRACES
using namespace ebcl;
using namespace ops;
using namespace opast;
namespace {
struct T_CompilerImpl_
{
T_Visitor< A_Node > astVisitor{ ASTVisitorBrowser };
T_Set< uint32_t > constants{ UseTag< IndexBacked< > >( ) };
T_ParserOutput* input;
P_OpProgram output;
uint32_t fiVariables , fiFramebuffers ,
fiPipelines , fiPrograms ,
fiSamplers , fiTextures;
P_OpProgram compile(
T_ParserOutput const& input ) noexcept;
private:
void gatherConstants( ) noexcept;
void countAssets( ) noexcept;
bool compileNode( uint32_t funcIndex ,
A_Node& node ,
bool exit ) noexcept;
};
P_OpProgram T_CompilerImpl_::compile(
T_ParserOutput const& in ) noexcept
{
input = const_cast< T_ParserOutput* >( &in );
output = NewOwned< T_OpProgram >( );
// Gather all constants used in expressions, count resources
gatherConstants( );
countAssets( );
// Get function indices
// FIXME ideally we should remap functions so that init is always 0
// 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
// Compile each function
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
astVisitor.visit( func ,
[=]( A_Node& node , const bool exit ) -> bool {
return compileNode( cfi , node , exit );
} );
}
return std::move( output );
}
void T_CompilerImpl_::gatherConstants( ) noexcept
{
constants.clear( );
astVisitor.visit( input->root , [&]( A_Node& node , const bool exit ) {
if ( exit && node.type( ) == A_Node::EXPR_CONST ) {
T_OpValue value;
value.f = dynamic_cast< T_ConstantExprNode& >( node ).floatValue( );
if ( value.f != 0 && value.f != 1 ) {
constants.add( value.u );
}
}
return true;
} );
#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" );
}
}
if ( constants.size( ) % 4 ) {
printf( "\n" );
}
#endif
}
void T_CompilerImpl_::countAssets( ) noexcept
{
auto const nt{ input->types.size( ) };
for ( auto i = 0u ; i < nt ; i ++ ) {
const auto t{ input->types.values( )[ i ] };
switch ( t ) {
case E_DataType::FRAMEBUFFER:
output->nFramebuffers ++;
break;
case E_DataType::PIPELINE:
output->nPipelines ++;
break;
case E_DataType::PROGRAM:
output->nPrograms ++;
break;
case E_DataType::SAMPLER:
output->nSamplers ++;
break;
case E_DataType::TEXTURE:
output->nTextures ++;
break;
case E_DataType::VARIABLE:
output->nVariables ++;
break;
case E_DataType::INPUT:
assert( !output->inputs.contains(
input->types.keys( )[ i ] ) );
output->inputs.add( input->types.keys( )[ i ] );
break;
case E_DataType::BUILTIN:
case E_DataType::UNKNOWN:
break;
}
}
fiVariables = 3 + constants.size( );
fiFramebuffers = fiVariables + output->nVariables;
fiPipelines = fiFramebuffers + output->nFramebuffers;
fiPrograms = fiPipelines + output->nPipelines;
fiSamplers = fiPrograms + output->nPrograms;
fiTextures = fiSamplers + output->nSamplers;
#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 );
#endif
}
bool T_CompilerImpl_::compileNode(
const uint32_t funcIndex ,
A_Node& node ,
const bool exit ) noexcept
{
return false;
}
}
/*= T_Compiler =================================================================*/
T_Compiler::T_Compiler( ) noexcept
: A_PrivateImplementation( new T_CompilerImpl_( ) )
{ }
P_OpProgram T_Compiler::compile(
T_ParserOutput const& input ) noexcept
{
return p< T_CompilerImpl_ >( ).compile( input );
}

View file

@ -1,5 +1,6 @@
#include "externals.hh"
#include "opast.hh"
#include "control.hh"
#include <ebcl/Files.hh>
#include <ebcl/SRDText.hh>
#include <ebcl/Algorithms.hh>
@ -34,17 +35,6 @@ void WriteSRDError(
}
/*============================================================================*/
T_Array< T_SRDError > parserPrototypes(
T_OwnPtr< T_ParserOutput > const& output )
{
T_Visitor< opast::A_Node > visitor{ ASTVisitorBrowser };
T_Array< T_SRDError > errors;
return errors;
}
/*============================================================================*/
} // namespace
@ -85,20 +75,10 @@ int main( int argc , char** argv )
// Parse the fuck
T_Parser parser;
if ( parser.parse( srdOut.list( ) ) ) {
printf( "Success - now running prototypes\n" );
T_Array< T_SRDError > errors{ parserPrototypes( parser.result( ) ) };
if ( errors.empty( ) ) {
printf( "Success!\n" );
printf( "Parser successful. Compiling...\n" );
ops::T_Compiler compiler;
compiler.compile( *parser.result( ) );
return 0;
}
T_StringBuilder sb;
for ( auto const& err : errors ) {
WriteSRDError( sb , err );
}
sb << "Parser prototypes failed\n" << '\0';
fprintf( stderr , "%s" , sb.data( ) );
return 4;
} else {
T_StringBuilder sb;
for ( auto const& err : parser.errors( ) ) {