From f1b51f564dbde3f28c597b1ec0ecb9d4be8a9f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sat, 2 Dec 2017 10:07:14 +0100 Subject: [PATCH] Optimizer - Errors when folding bad operations Errors will be added to an array if the optimizer finds invalid operations involving constants (e.g. (inv 0)) --- c-opopt.cc | 176 +++++++++++++++++++++++++++++------------------------ c-opopt.hh | 42 +++++++------ 2 files changed, 120 insertions(+), 98 deletions(-) diff --git a/c-opopt.cc b/c-opopt.cc index 5d44870..a995579 100644 --- a/c-opopt.cc +++ b/c-opopt.cc @@ -1,6 +1,8 @@ #include "externals.hh" +#include "c-opcomp.hh" #include "c-opopt.hh" +#include "c-ops.hh" #include "c-sync.hh" using namespace ebcl; @@ -8,26 +10,15 @@ 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; + T_ConstantFolder_( T_OptData& data ) noexcept + : oData{ data } + {} // Result bool didFold{ false }; @@ -35,6 +26,8 @@ struct T_ConstantFolder_ bool operator()( A_Node& node , bool exit ) noexcept; private: + T_OptData& oData; + template< typename T > void handleParentNode( @@ -52,14 +45,12 @@ struct T_ConstantFolder_ // Transform an unary operator applied to a constant into a constant. P_ExpressionNode doUnaryOp( - A_Node& parent , - T_UnaryOperatorNode::E_Operator op , + T_UnaryOperatorNode& node , double value ) const noexcept; // Transform a binary operator applied to a constant into a constant. P_ExpressionNode doBinaryOp( - A_Node& parent , - T_BinaryOperatorNode::E_Operator op , + T_BinaryOperatorNode& node , double left , double right ) const noexcept; }; @@ -135,12 +126,12 @@ P_ExpressionNode T_ConstantFolder_::checkExpression( // Replace inputs with value if no curve/constant curve if ( node.type( ) == A_Node::EXPR_INPUT ) { - if ( !curves ) { + if ( !oData.curves ) { return {}; } auto& n{ (T_InputExprNode&) node }; - auto const* const curve{ curves->curves.get( n.id( ) ) }; + auto const* const curve{ oData.curves->curves.get( n.id( ) ) }; if ( curve ) { // Curve present, check if it's constant const auto cval{ curve->isConstant( ) }; @@ -163,8 +154,7 @@ P_ExpressionNode T_ConstantFolder_::checkExpression( []( auto& n , P_ExpressionNode e ) { n.setArgument( std::move( e ) ); } ); if ( asUnary->argument( ).type( ) == A_Node::EXPR_CONST ) { auto const& cn{ (T_ConstantExprNode const&) asUnary->argument( ) }; - return doUnaryOp( asUnary->parent( ) , asUnary->op( ) , - cn.floatValue( ) ); + return doUnaryOp( *asUnary , cn.floatValue( ) ); } return {}; } @@ -183,8 +173,7 @@ P_ExpressionNode T_ConstantFolder_::checkExpression( && asBinary->right( ).type( ) == A_Node::EXPR_CONST ) { auto const& l{ (T_ConstantExprNode const&) asBinary->left( ) }; auto const& r{ (T_ConstantExprNode const&) asBinary->right( ) }; - return doBinaryOp( asBinary->parent( ) , asBinary->op( ), - l.floatValue( ) , r.floatValue( ) ); + return doBinaryOp( *asBinary , l.floatValue( ) , r.floatValue( ) ); } return {}; } @@ -194,98 +183,132 @@ P_ExpressionNode T_ConstantFolder_::checkExpression( P_ExpressionNode T_ConstantFolder_::doIdExpr( T_IdentifierExprNode& node ) noexcept { - if ( !fixedSize ) { + if ( !oData.fixedSize ) { return {}; } if ( node.id( ) == "width" ) { return NewOwned< T_ConstantExprNode >( node.parent( ) , - double( fixedSize->first ) ); + double( oData.fixedSize->first ) ); } if ( node.id( ) == "height" ) { return NewOwned< T_ConstantExprNode >( node.parent( ) , - float( fixedSize->second ) ); + float( oData.fixedSize->second ) ); } return {}; } P_ExpressionNode T_ConstantFolder_::doUnaryOp( - A_Node& parent , - const T_UnaryOperatorNode::E_Operator op , + T_UnaryOperatorNode& node , const double value ) const noexcept { - const double rVal{ []( const auto op , const auto value ) { - switch ( op ) { + const double rVal{ [this]( auto& node , const auto value ) { + switch ( node.op( ) ) { + case T_UnaryOperatorNode::NEG: return -value; + case T_UnaryOperatorNode::NOT: return value ? 0. : 1.; + case T_UnaryOperatorNode::INV: - // TODO check if 0 + if ( value == 0 ) { + oData.errors.addNew( "math - 1/x, x=0" , node.location( ) ); + return 0.; + } return 1. / value; + case T_UnaryOperatorNode::COS: return cos( value ); + case T_UnaryOperatorNode::SIN: return sin( value ); + case T_UnaryOperatorNode::TAN: - // TODO check if valid + if ( fabs( value - M_PI / 2 ) <= 1e-6 ) { + oData.errors.addNew( "math - tan(x), x=~PI/2" , + node.location( ) , E_SRDErrorType::WARNING ); + } return tan( value ); + case T_UnaryOperatorNode::SQRT: - // TODO check if >= 0 + if ( value < 0 ) { + oData.errors.addNew( "math - sqrt(x), x<0" , node.location( ) ); + return 0.; + } return sqrt( value ); + case T_UnaryOperatorNode::LN: - // TODO check if > 0 + if ( value <= 0 ) { + oData.errors.addNew( "math - ln(x), x<=0" , node.location( ) ); + return 0.; + } return log( value ); + case T_UnaryOperatorNode::EXP: return exp( value ); } - fprintf( stderr , "invalid operator %d\n" , int( op ) ); - std::abort( ); - }( op , value ) }; - return NewOwned< T_ConstantExprNode >( parent , rVal ); + fprintf( stderr , "invalid operator %d\n" , int( node.op( ) ) ); + std::abort( ); + }( node , value ) }; + + return NewOwned< T_ConstantExprNode >( node.parent( ) , rVal ); } P_ExpressionNode T_ConstantFolder_::doBinaryOp( - A_Node& parent , - const T_BinaryOperatorNode::E_Operator op , + T_BinaryOperatorNode& node , const double left , const double right ) const noexcept { - const double rVal{ []( const auto op , const auto l , const auto r ) { - switch ( op ) { + const double rVal{ [this]( auto& node , const auto l , const auto r ) { + switch ( node.op( ) ) { + case T_BinaryOperatorNode::ADD: return l + r; + case T_BinaryOperatorNode::SUB: return l - r; + case T_BinaryOperatorNode::MUL: return l * r; - case T_BinaryOperatorNode::DIV: - // TODO: check r != 0 - return l / r; - case T_BinaryOperatorNode::POW: - // TODO check operands - return pow( l , r ); - case T_BinaryOperatorNode::CMP_EQ: - return ( l == r ) ? 1. : 0.; - case T_BinaryOperatorNode::CMP_NE: - return ( l != r ) ? 1. : 0.; - case T_BinaryOperatorNode::CMP_GT: - return ( l > r ) ? 1. : 0.; - case T_BinaryOperatorNode::CMP_GE: - return ( l >= r ) ? 1. : 0.; - case T_BinaryOperatorNode::CMP_LT: - return ( l < r ) ? 1. : 0.; - case T_BinaryOperatorNode::CMP_LE: - return ( l <= r ) ? 1. : 0.; - } - fprintf( stderr , "invalid operator %d\n" , int( op ) ); - std::abort( ); - }( op , left , right ) }; - return NewOwned< T_ConstantExprNode >( parent , rVal ); + case T_BinaryOperatorNode::DIV: + if ( r == 0 ) { + oData.errors.addNew( "math - l/r, r=0" , node.location( ) ); + return 0.; + } + return l / r; + + case T_BinaryOperatorNode::POW: + if ( l == 0 && r == 0 ) { + oData.errors.addNew( "math - l^r, l=r=0" , node.location( ) ); + return 0.; + } + if ( l == 0 && r < 0 ) { + oData.errors.addNew( "math - l^r, l=0, r<0" , node.location( ) ); + return 0.; + } + if ( l < 0 && fmod( r , 1. ) != 0. ) { + oData.errors.addNew( "math - l^r, l<0, r not integer" , node.location( ) ); + return 0.; + } + return pow( l , r ); + + case T_BinaryOperatorNode::CMP_EQ: return ( l == r ) ? 1. : 0.; + case T_BinaryOperatorNode::CMP_NE: return ( l != r ) ? 1. : 0.; + case T_BinaryOperatorNode::CMP_GT: return ( l > r ) ? 1. : 0.; + case T_BinaryOperatorNode::CMP_GE: return ( l >= r ) ? 1. : 0.; + case T_BinaryOperatorNode::CMP_LT: return ( l < r ) ? 1. : 0.; + case T_BinaryOperatorNode::CMP_LE: return ( l <= r ) ? 1. : 0.; + } + fprintf( stderr , "invalid operator %d\n" , int( node.op( ) ) ); + std::abort( ); + }( node , left , right ) }; + + return NewOwned< T_ConstantExprNode >( node.parent( ) , rVal ); } } // namespace @@ -294,27 +317,20 @@ P_ExpressionNode T_ConstantFolder_::doBinaryOp( 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 + T_OpsParserOutput& program , + T_OptData& oData ) noexcept { - M_VISITOR_( extVisitor ); - T_ConstantFolder_ folder; - folder.fixedSize = fixedSize; - folder.curves = curves; - visitor.visit( root , folder ); + T_ConstantFolder_ folder{ oData }; + oData.visitor.visit( program.root , folder ); return folder.didFold; } /*= DEAD CODE REMOVAL ========================================================*/ -bool opopt::RemoveDeadCode( opast::T_RootNode& root , - ebcl::T_Visitor< opast::A_Node >* extVisitor ) noexcept +bool opopt::RemoveDeadCode( + T_OpsParserOutput& program , + T_OptData& oData ) noexcept { - M_VISITOR_( extVisitor ); - -#warning blargh return false; } diff --git a/c-opopt.hh b/c-opopt.hh index ed4fe3e..2e1a600 100644 --- a/c-opopt.hh +++ b/c-opopt.hh @@ -3,35 +3,41 @@ #include +struct T_OpsParserOutput; struct T_SyncCurves; namespace opopt { +// Persistent data for the various stages of the optimizer. +struct T_OptData +{ + // List of errors generated by the optimizer + T_Array< ebcl::T_SRDError > errors; + + // If the size of the ouput is fixed, this field contains it as a + // pair. + T_Optional< std::pair< uint32_t , uint32_t > > fixedSize; + + // The curves that will be bound to the inputs. + T_SyncCurves const* curves; + + // A visitor to be used for the tree + ebcl::T_Visitor< opast::A_Node > visitor{ opast::ASTVisitorBrowser }; +}; + +/*----------------------------------------------------------------------------*/ + // 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; +bool FoldConstants( T_OpsParserOutput& program , + T_OptData& optData ) 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; +bool RemoveDeadCode( T_OpsParserOutput& program , + T_OptData& optData ) noexcept; } // namespace opopt