Optimizer - Began working on constant folding

This commit is contained in:
Emmanuel BENOîT 2017-12-01 07:30:03 +01:00
parent 59b23de5ed
commit 0175bed077
4 changed files with 218 additions and 2 deletions

View file

@ -34,6 +34,7 @@ COMMON = \
\
c-ops.cc \
c-opast.cc \
c-opopt.cc \
c-opparser.cc \
c-opcomp.cc \
c-opmgr.cc \

View file

@ -215,6 +215,9 @@ class T_ArgumentNode : public A_Node
{ return *expr_; }
bool isIdentifier( ) const noexcept
{ return expr_->type( ) == EXPR_ID; }
void expression( P_ExpressionNode expr ) noexcept
{ assert( expr ); expr_ = std::move( expr ); }
};
using P_ArgumentNode = T_OwnPtr< T_ArgumentNode >;
@ -454,6 +457,9 @@ class T_CondInstrNode : public A_InstructionNode
A_ExpressionNode& expression( ) const noexcept
{ return *expression_; }
void expression( P_ExpressionNode expr ) noexcept
{ assert( expr ); expression_ = std::move( expr ); }
};
class T_ValuedCase : public A_Node
@ -1216,8 +1222,8 @@ class T_ConstantExprNode : public A_ExpressionNode
T_ConstantExprNode( A_Node& parent ,
int64_t value ) noexcept
: A_ExpressionNode( EXPR_CONST , parent ) , wasFloat_( false ) ,
vFloat_( value ) , vInt_( value )
: A_ExpressionNode( EXPR_CONST , parent ) , wasFloat_( false ) ,
vFloat_( value ) , vInt_( value )
{ }
T_ConstantExprNode( A_Node& parent ,

172
c-opopt.cc Normal file
View file

@ -0,0 +1,172 @@
#include "externals.hh"
#include "c-opopt.hh"
#include "c-sync.hh"
using namespace ebcl;
using namespace opast;
using namespace opopt;
// Macro to use either the specified visitor or a visitor created just for the
// occation
#define M_VISITOR_( E ) \
T_OwnPtr< T_Visitor< A_Node > > localVisitor_; \
if ( !(E) ) { \
localVisitor_ = NewOwned< T_Visitor< A_Node > >( ASTVisitorBrowser ); \
} \
T_Visitor< A_Node >& visitor{ (E) ? *(E) : *localVisitor_ }
/*= CONSTANT FOLDING =========================================================*/
namespace {
struct T_ConstantFolder_
{
// Input
T_Optional< std::pair< uint32_t , uint32_t > > fixedSize;
T_SyncCurves const* curves;
// Result
bool didFold{ false };
bool operator()( A_Node& node , bool exit ) noexcept;
private:
using F_ExprGet_ = std::function< A_ExpressionNode&( A_Node& ) >;
using F_ExprSet_ = std::function< void( A_Node& , P_ExpressionNode ) >;
void handleParentNode(
A_Node& node ,
F_ExprGet_ get ,
F_ExprSet_ set ) noexcept;
P_ExpressionNode checkExpression(
A_ExpressionNode const& node ) noexcept;
};
/*----------------------------------------------------------------------------*/
bool T_ConstantFolder_::operator()(
A_Node& node ,
const bool exit ) noexcept
{
if ( exit ) {
return true;
}
switch ( node.type( ) ) {
case A_Node::TN_ARG:
handleParentNode( node ,
[]( A_Node& n ) -> A_ExpressionNode& {
return ((T_ArgumentNode&)n).expression( );
} ,
[]( A_Node& n , P_ExpressionNode e ) {
((T_ArgumentNode&)n).expression( std::move( e ) );
} );
return false;
case A_Node::TN_CONDITION:
handleParentNode( node ,
[]( A_Node& n ) -> A_ExpressionNode& {
return ((T_CondInstrNode::T_Expression&)n).expression( );
} ,
[]( A_Node& n , P_ExpressionNode e ) {
((T_CondInstrNode::T_Expression&)n).expression( std::move( e ) );
} );
return false;
case A_Node::OP_SET:
handleParentNode( node ,
[]( A_Node& n ) -> A_ExpressionNode& {
return ((T_SetInstrNode&)n).expression( );
} ,
[]( A_Node& n , P_ExpressionNode e ) {
((T_SetInstrNode&)n).setExpression( std::move( e ) );
} );
return false;
default:
return true;
}
}
void T_ConstantFolder_::handleParentNode(
A_Node& node ,
F_ExprGet_ get ,
F_ExprSet_ set ) noexcept
{
auto r{ checkExpression( get( node ) ) };
if ( r ) {
set( node , std::move( r ) );
didFold = true;
}
}
/*----------------------------------------------------------------------------*/
P_ExpressionNode T_ConstantFolder_::checkExpression(
A_ExpressionNode const& node ) noexcept
{
#warning TODO optimize the fuck
// 1/ Replace inputs with value if no curve/constant curve
// Replace $width/$height with value if fixedSize
// 2/ Replace UnOp( Cnst ) with result
// Replace BinOp( Cnst , Cnst ) with result
// 3/ Try to find other optimisations, e.g. for Add( Cnst , Add( Cnst , Expr ) )
if ( node.type( ) == A_Node::EXPR_ID ) {
if ( !fixedSize ) {
return {};
}
T_IdentifierExprNode& n{ (T_IdentifierExprNode&) node };
if ( n.id( ) == "width" ) {
auto c{ NewOwned< T_ConstantExprNode >( n.parent( ) ,
double( fixedSize->first ) ) };
c->location( ) = n.location( );
return c;
}
if ( n.id( ) == "height" ) {
auto c{ NewOwned< T_ConstantExprNode >( n.parent( ) ,
float( fixedSize->second ) ) };
c->location( ) = n.location( );
return c;
}
return {};
}
return {};
}
} // namespace <anon>
bool opopt::FoldConstants(
T_RootNode& root ,
const T_Optional< std::pair< uint32_t , uint32_t > > fixedSize ,
T_SyncCurves const* curves ,
T_Visitor< A_Node >* const extVisitor ) noexcept
{
M_VISITOR_( extVisitor );
T_ConstantFolder_ folder;
folder.fixedSize = fixedSize;
folder.curves = curves;
visitor.visit( root , folder );
return folder.didFold;
}
/*= DEAD CODE REMOVAL ========================================================*/
bool opopt::RemoveDeadCode( opast::T_RootNode& root ,
ebcl::T_Visitor< opast::A_Node >* extVisitor ) noexcept
{
M_VISITOR_( extVisitor );
#warning blargh
return false;
}

37
c-opopt.hh Normal file
View file

@ -0,0 +1,37 @@
#pragma once
#include "c-opast.hh"
#include <ebcl/Algorithms.hh>
struct T_SyncCurves;
namespace opopt {
// Attempts to fold constant expressions into single constants. Returns true if
// transformations were made, false if not.
//
// Parameters:
// root the root node
// fixedSize the size of the output, if it is fixed
// curves the curves that will be bound to the inputs
// extVisitor a node visitor instance to be used instead of creating
// one
//
bool FoldConstants( opast::T_RootNode& root ,
T_Optional< std::pair< uint32_t , uint32_t > > fixedSize = { } ,
T_SyncCurves const* curves = nullptr ,
ebcl::T_Visitor< opast::A_Node >* extVisitor = nullptr ) 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.
//
// Parameters:
// root the root node
// extVisitor a node visitor instance to be used instead of creating
// one
//
bool RemoveDeadCode( opast::T_RootNode& root ,
ebcl::T_Visitor< opast::A_Node >* extVisitor = nullptr ) noexcept;
} // namespace opopt