diff --git a/c-opast.cc b/c-opast.cc index f16b332..ceb1b17 100644 --- a/c-opast.cc +++ b/c-opast.cc @@ -32,6 +32,15 @@ T_RootNode& A_Node::root( ) const noexcept const_cast< A_Node* >( node ) ); } +void A_Node::replaceChild( + A_Node const& /*child*/ , + T_OwnPtr< A_Node > /*replacement*/ + ) noexcept +{ + fprintf( stderr , "replaceChild called on invalid node\n" ); + std::terminate( ); +} + /*----------------------------------------------------------------------------*/ A_Node* opast::ASTVisitorBrowser( @@ -492,6 +501,19 @@ T_BinaryOperatorNode::T_BinaryOperatorNode( })( ) , parent ) , op_( op ) { } +void T_BinaryOperatorNode::replaceChild( + A_Node const& child , + T_OwnPtr< A_Node > replacement + ) noexcept +{ + if ( right_.get( ) == &child ) { + right_ = std::move( replacement ); + } else { + assert( left_.get( ) == &child ); + left_ = std::move( replacement ); + } +} + /*= T_FramebufferInstrNode ===================================================*/ @@ -629,7 +651,17 @@ T_Optional< T_SRDLocation > T_LocalsInstrNode::addVariable( } -/*= T_CondInstrNode ============================================================*/ +/*= T_CondInstrNode ==========================================================*/ + +void T_CondInstrNode::T_Expression::replaceChild( + A_Node const& child , + T_OwnPtr< A_Node > replacement ) noexcept +{ + assert( expression_.get( ) == &child ); + expression_ = std::move( replacement ); +} + +/*----------------------------------------------------------------------------*/ void T_CondInstrNode::setExpression( P_ExpressionNode expression ) noexcept diff --git a/c-opast.hh b/c-opast.hh index 4a499e5..bb5eb19 100644 --- a/c-opast.hh +++ b/c-opast.hh @@ -94,6 +94,10 @@ class A_Node { assert( parent_ ); return *parent_; } T_RootNode& root( ) const noexcept; + + virtual void replaceChild( + A_Node const& child , + T_OwnPtr< A_Node > replacement ) noexcept; }; // Browser function to be used with T_Visitor @@ -460,6 +464,10 @@ class T_CondInstrNode : public A_InstructionNode void expression( P_ExpressionNode expr ) noexcept { assert( expr ); expression_ = std::move( expr ); } + + void replaceChild( + A_Node const& child , + T_OwnPtr< A_Node > replacement ) noexcept override; }; class T_ValuedCase : public A_Node @@ -1362,6 +1370,10 @@ class T_BinaryOperatorNode : public A_ExpressionNode { return *right_; } A_ExpressionNode& right( ) noexcept { return *right_; } + + void replaceChild( + A_Node const& child , + T_OwnPtr< A_Node > replacement ) noexcept override; }; diff --git a/c-opopt.cc b/c-opopt.cc index d23323c..5ed3864 100644 --- a/c-opopt.cc +++ b/c-opopt.cc @@ -1441,6 +1441,41 @@ bool opopt::FoldConstants( /*= CONSTANT PROPAGATION =====================================================*/ +namespace { + +void CPReplaceWithConstant_( + A_InstructionNode& instruction , + T_OptData::T_VarId const& var , + const double value , + T_OptData& oData + ) noexcept +{ + oData.visitor.visit( instruction , [&]( A_Node& node , const bool exit ) { + if ( !exit || node.type( ) != A_Node::EXPR_ID ) { + return node.type( ) != A_Node::ILIST; + } + + auto& eid{ (T_IdentifierExprNode&) node }; + if ( eid.id( ) != var.name ) { + return true; + } + + auto& p{ eid.parent( ) }; + auto replacement{ NewOwned< T_ConstantExprNode >( p , value ) }; + replacement->location( ) = eid.location( ); + p.replaceChild( eid , std::move( replacement ) ); + oData.logger( [&]() { + T_StringBuilder sb; + sb << "Propagated constant from " << var.name + << " at " << instruction.location( ) + << " (value " << value << ")"; + return sb; + } , LL2 ); + return true; + } ); +} + +} // namespace bool opopt::PropagateConstants( T_OpsParserOutput& program , @@ -1463,7 +1498,67 @@ bool opopt::PropagateConstants( oData.buildUseDefineChains( program ); M_LOGSTR_( "... Propagating constants" , 2 ); - return false; + T_Set< uint32_t > cDefs{ UseTag< ArrayBacked< 16 > >( ) }; + T_AutoArray< double , 16 > cValues; + bool changesMade{ false }; + for ( auto const& udc : oData.varUDChains.values( ) ) { + cDefs.clear( ); + cValues.clear( ); + + // Find all constant definitions + const auto nDefs{ udc.defines.size( ) }; + for ( auto i = 0u ; i < nDefs ; i ++ ) { + auto const& def{ udc.defines[ i ] }; + auto const* const ri{ oData.instructions[ def.node ].node }; + if ( ri->type( ) == A_Node::OP_SET ) { + auto const* const si{ + dynamic_cast< T_SetInstrNode const* >( ri ) }; + if ( si->expression( ).type( ) == A_Node::EXPR_CONST ) { + cDefs.add( i ); + cValues.add( ( (T_ConstantExprNode&) si->expression( ) ).floatValue( ) ); + } + } else { + // Instruction is not supported, exit + assert( cDefs.size( ) == 0 ); + break; + } + } + assert( cValues.size( ) == cDefs.size( ) ); + if ( cValues.empty( ) ) { + continue; + } + + const auto nUses{ udc.uses.size( ) }; + for ( auto i = 0u ; i < nUses ; i ++ ) { + auto const& use{ udc.uses[ i ] }; + const auto nRefs{ use.refs.size( ) }; + T_Optional< double > repVal{ }; + for ( auto j = 0u ; j < nRefs ; j ++ ) { + const auto dIdx{ cDefs.indexOf( use.refs[ j ] ) }; + if ( dIdx == -1 ) { + repVal.clear( ); + break; + } + if ( !repVal ) { + repVal = cValues[ dIdx ]; + } else if ( *repVal != cValues[ dIdx ] ) { + repVal.clear( ); + break; + } + } + if ( !repVal ) { + continue; + } + + printf( "Could replace use at %d with constant %f\n" , + use.node , *repVal ); + CPReplaceWithConstant_( *oData.instructions[ use.node ].node , + udc.var , *repVal , oData ); + changesMade = true; + } + } + + return changesMade; } diff --git a/test/build.srd b/test/build.srd index 139ec1d..bd62872 100644 --- a/test/build.srd +++ b/test/build.srd @@ -4,7 +4,9 @@ (1920 1080) ) (optimizer on - (constant-folding on) + (constant-folding on + # (fixed-resolution on) + ) (constant-propagation on) ) )