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:
parent
f574780c5e
commit
efa1b26150
4 changed files with 144 additions and 3 deletions
34
c-opast.cc
34
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
|
||||
|
|
12
c-opast.hh
12
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;
|
||||
};
|
||||
|
||||
|
||||
|
|
97
c-opopt.cc
97
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 <anon>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
(1920 1080)
|
||||
)
|
||||
(optimizer on
|
||||
(constant-folding on)
|
||||
(constant-folding on
|
||||
# (fixed-resolution on)
|
||||
)
|
||||
(constant-propagation on)
|
||||
)
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue