Optimizer - Remove dead branches

This commit is contained in:
Emmanuel BENOîT 2017-12-16 10:38:17 +01:00
parent 08e486a57c
commit ab279857fa
3 changed files with 154 additions and 44 deletions

View file

@ -447,6 +447,50 @@ uint32_t T_FuncNode::arguments( ) const noexcept
return na; return na;
} }
/*= T_InstrListNode ==========================================================*/
void T_InstrListNode::replaceMultiple(
A_InstructionNode& instruction ,
T_InstrListNode* replacement
) noexcept
{
T_OwnPtr< A_InstructionNode > oldInstr;
uint32_t index{ 0xffffffff };
for ( auto i = 0u ; i < children_.size( ) ; i ++ ) {
if ( children_[ i ].get( ) == &instruction ) {
oldInstr = std::move( children_[ i ] );
index = i;
break;
}
}
assert( oldInstr );
if ( replacement ) {
auto& rep{ *replacement };
// Move existing children to the end of the list
const auto oldSize{ children_.size( ) };
for ( auto i = 1u ; i < rep.size( ) ; i ++ ) {
children_.addNew( );
}
const auto newSize{ children_.size( ) };
const auto nMove{ oldSize + 1 - index };
for ( auto i = 1u ; i < nMove ; i ++ ) {
children_[ newSize - i ] = std::move(
children_[ oldSize - i ] );
}
// Move replacement instructions
for ( auto i = 0u ; i < rep.size( ) ; i ++ ) {
children_[ index + i ] = std::move(
rep.children_[ i ] );
children_[ index + i ]->setParent( *this );
}
} else {
children_.remove( index );
}
}
/*= T_PipelineInstrNode ======================================================*/ /*= T_PipelineInstrNode ======================================================*/

View file

@ -72,7 +72,7 @@ class A_Node
private: private:
const E_Type type_; const E_Type type_;
A_Node* const parent_; A_Node* parent_;
ebcl::T_SRDLocation location_; ebcl::T_SRDLocation location_;
protected: protected:
@ -109,6 +109,9 @@ class A_Node
bool replace( A_Node const& node , bool replace( A_Node const& node ,
T_OwnPtr< A_Node >& replacement ) noexcept; T_OwnPtr< A_Node >& replacement ) noexcept;
void setParent( A_Node& newParent ) noexcept
{ parent_ = &newParent; }
}; };
// Browser function to be used with T_Visitor // Browser function to be used with T_Visitor
@ -178,6 +181,10 @@ class T_InstrListNode : public A_Node
A_InstructionNode& node( const uint32_t index ) const noexcept A_InstructionNode& node( const uint32_t index ) const noexcept
{ return dynamic_cast< A_InstructionNode& >( *children_[ index ] ); } { return dynamic_cast< A_InstructionNode& >( *children_[ index ] ); }
void replaceMultiple(
A_InstructionNode& instruction ,
T_InstrListNode* replacement ) noexcept;
}; };
template< template<

View file

@ -497,10 +497,12 @@ void T_OptData::buildControlFlowGraph(
return; return;
} }
numberInstructions( program ); numberInstructions( program );
M_LOGSTR_( "Building control flow graph" , 4 );
// Keep the old array, we'll reuse its contents // Keep the old array, we'll reuse its contents
T_Array< P_CtrlFlowNode > old{ std::move( ctrlFlowGraph ) }; T_Array< P_CtrlFlowNode > old{ std::move( ctrlFlowGraph ) };
M_LOGSTR_( "Building control flow graph" , 4 ); callSites.clear( );
cfgFunctions.clear( );
// Create special nodes // Create special nodes
M_ADDNEW_( ); M_ADDNEW_( );
@ -512,7 +514,6 @@ void T_OptData::buildControlFlowGraph(
// Generate control flow graph for each function // Generate control flow graph for each function
T_BCFGStack_ stack; T_BCFGStack_ stack;
T_Optional< uint32_t > cNode{ }; T_Optional< uint32_t > cNode{ };
callSites.clear( );
visitor.visit( program.root , [&]( A_Node& node , const bool exit ) { visitor.visit( program.root , [&]( A_Node& node , const bool exit ) {
return BCFGVisitor_( node , exit , *this , return BCFGVisitor_( node , exit , *this ,
stack , cNode , old ); stack , cNode , old );
@ -1568,54 +1569,112 @@ bool opopt::PropagateConstants(
/*= DEAD CODE REMOVAL ========================================================*/ /*= DEAD CODE REMOVAL ========================================================*/
namespace {
bool opopt::RemoveDeadCode( struct T_RDCConstCond_
T_OpsParserOutput& program ,
T_OptData& oData ) noexcept
{ {
oData.buildUseDefineChains( program );
M_LOGSTR_( "... Eliminating dead code" , 2 );
struct T_ConstCond_ {
T_CondInstrNode* node; T_CondInstrNode* node;
int64_t value; int64_t value;
}; };
T_AutoArray< T_ConstCond_ , 16 > constConds; using T_RDCConstCondList_ = T_AutoArray< T_RDCConstCond_ , 16 >;
oData.visitor.visit( program.root , [&]( A_Node& node , const bool exit ) {
const auto nt{ node.type( ) }; bool RDCFindConditionals_(
A_Node& node ,
const bool exit ,
T_RDCConstCondList_& constConds
) noexcept
{
if ( exit || node.type( ) != A_Node::OP_COND ) {
return !dynamic_cast< A_ExpressionNode* >( &node );
}
if ( !exit && nt == A_Node::OP_COND ) {
auto& cn{ dynamic_cast< T_CondInstrNode& >( node ) }; auto& cn{ dynamic_cast< T_CondInstrNode& >( node ) };
auto const& ce{ cn.expression( ).expression( ) }; auto const& ce{ cn.expression( ).expression( ) };
if ( ce.type( ) == A_Node::EXPR_CONST ) { if ( ce.type( ) == A_Node::EXPR_CONST ) {
const int64_t ccv{ ( (T_ConstantExprNode const&) ce ).intValue( ) }; const int64_t ccv{ ( (T_ConstantExprNode const&) ce ).intValue( ) };
constConds.add( T_ConstCond_{ &cn , ccv } ); constConds.add( T_RDCConstCond_{ &cn , ccv } );
return false; return false;
} }
return true;
}
bool RDCConditionals_(
T_OpsParserOutput& program ,
T_OptData& oData
) noexcept
{
M_LOGSTR_( "...... Checking conditional instructions" , 3 );
T_RDCConstCondList_ constConds;
oData.visitor.visit( program.root , [&]( A_Node& node , const bool exit ) {
return RDCFindConditionals_( node , exit , constConds );
} );
if ( !constConds.size( ) ) {
return false;
} }
return !dynamic_cast< A_ExpressionNode* >( &node );
} );
if ( constConds.size( ) ) {
const auto ncc{ constConds.size( ) }; const auto ncc{ constConds.size( ) };
for ( auto i = 0u ; i < ncc ; i ++ ) { for ( auto i = 0u ; i < ncc ; i ++ ) {
auto const& cc{ constConds[ i ] }; auto const& cc{ constConds[ i ] };
auto& cn{ *cc.node }; auto& cn{ *cc.node };
T_InstrListNode* replacement; T_InstrListNode* replacement;
printf( "IF (CNST: %ld)!!!\n" , cc.value ); oData.logger( [&](){
T_StringBuilder sb;
sb << "......... Conditional with constant argument at "
<< cn.location( );
return sb;
} , 4 );
if ( cn.hasCase( cc.value ) ) { if ( cn.hasCase( cc.value ) ) {
printf( "Will replace with case\n" );
replacement = &cn.getCase( cc.value ).instructions( ); replacement = &cn.getCase( cc.value ).instructions( );
oData.logger( [&](){
T_StringBuilder sb;
sb << "Will replace with case for value "
<< cc.value << " ("
<< replacement->location( ) << ")";
return sb;
} , 5 );
} else if ( cn.hasDefaultCase( ) ) { } else if ( cn.hasDefaultCase( ) ) {
printf( "Will replace with default\n" );
replacement = &cn.defaultCase( ).instructions( ); replacement = &cn.defaultCase( ).instructions( );
oData.logger( [&](){
T_StringBuilder sb;
sb << "Will replace with default case ("
<< replacement->location( ) << ")";
return sb;
} , 5 );
} else { } else {
printf( "DELETE! DELETE! DELETE!\n" ); M_LOGSTR_( "Will delete whole instruction" , 5 );
replacement = nullptr; replacement = nullptr;
} }
} ( (T_InstrListNode&) cn.parent( ) ).replaceMultiple( cn , replacement );
} }
return false; oData.state = {};
return true;
}
} // namespace <anon>
/*----------------------------------------------------------------------------*/
bool opopt::RemoveDeadCode(
T_OpsParserOutput& program ,
T_OptData& oData ) noexcept
{
// oData.buildUseDefineChains( program );
M_LOGSTR_( "... Eliminating dead code" , 2 );
bool didStuff{ false };
// bool tryDeadStoresFirst{ oData.state & T_OptData::E_StateItem::UDCHAINS };
bool didStuffThisTime;
do {
didStuffThisTime = RDCConditionals_( program , oData );
didStuff = didStuff || didStuffThisTime;
} while ( didStuffThisTime );
if ( didStuff ) {
M_LOGSTR_( "...... Dead code removed" , 3 );
} else {
M_LOGSTR_( "...... No dead code found" , 3 );
}
return didStuff;
} }