Optimizer - Constant propagation for variables

* It doesn't work for function arguments at this point, but shouldn't be
too hard to implement that.
* Can't use it to its full potential mostly because I need to get rid of
the node-specific shit in the AST.
This commit is contained in:
Emmanuel BENOîT 2017-12-12 18:30:41 +01:00
parent f574780c5e
commit efa1b26150
4 changed files with 144 additions and 3 deletions

View file

@ -32,6 +32,15 @@ T_RootNode& A_Node::root( ) const noexcept
const_cast< A_Node* >( node ) ); 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( A_Node* opast::ASTVisitorBrowser(
@ -492,6 +501,19 @@ T_BinaryOperatorNode::T_BinaryOperatorNode(
})( ) , parent ) , op_( op ) })( ) , 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 ===================================================*/ /*= 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( void T_CondInstrNode::setExpression(
P_ExpressionNode expression ) noexcept P_ExpressionNode expression ) noexcept

View file

@ -94,6 +94,10 @@ class A_Node
{ assert( parent_ ); return *parent_; } { assert( parent_ ); return *parent_; }
T_RootNode& root( ) const noexcept; 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 // Browser function to be used with T_Visitor
@ -460,6 +464,10 @@ class T_CondInstrNode : public A_InstructionNode
void expression( P_ExpressionNode expr ) noexcept void expression( P_ExpressionNode expr ) noexcept
{ assert( expr ); expression_ = std::move( expr ); } { 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 class T_ValuedCase : public A_Node
@ -1362,6 +1370,10 @@ class T_BinaryOperatorNode : public A_ExpressionNode
{ return *right_; } { return *right_; }
A_ExpressionNode& right( ) noexcept A_ExpressionNode& right( ) noexcept
{ return *right_; } { return *right_; }
void replaceChild(
A_Node const& child ,
T_OwnPtr< A_Node > replacement ) noexcept override;
}; };

View file

@ -1441,6 +1441,41 @@ bool opopt::FoldConstants(
/*= CONSTANT PROPAGATION =====================================================*/ /*= 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 <anon>
bool opopt::PropagateConstants( bool opopt::PropagateConstants(
T_OpsParserOutput& program , T_OpsParserOutput& program ,
@ -1463,7 +1498,67 @@ bool opopt::PropagateConstants(
oData.buildUseDefineChains( program ); oData.buildUseDefineChains( program );
M_LOGSTR_( "... Propagating constants" , 2 ); 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;
} }

View file

@ -4,7 +4,9 @@
(1920 1080) (1920 1080)
) )
(optimizer on (optimizer on
(constant-folding on) (constant-folding on
# (fixed-resolution on)
)
(constant-propagation on) (constant-propagation on)
) )
) )