From ab279857fa276d1cc4af4250c3f2e237c0af3289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sat, 16 Dec 2017 10:38:17 +0100 Subject: [PATCH] Optimizer - Remove dead branches --- c-opast.cc | 44 ++++++++++++++++ c-opast.hh | 9 +++- c-opopt.cc | 145 +++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 154 insertions(+), 44 deletions(-) diff --git a/c-opast.cc b/c-opast.cc index 0b60234..788bfa9 100644 --- a/c-opast.cc +++ b/c-opast.cc @@ -447,6 +447,50 @@ uint32_t T_FuncNode::arguments( ) const noexcept 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 ======================================================*/ diff --git a/c-opast.hh b/c-opast.hh index a36707f..b457c96 100644 --- a/c-opast.hh +++ b/c-opast.hh @@ -72,7 +72,7 @@ class A_Node private: const E_Type type_; - A_Node* const parent_; + A_Node* parent_; ebcl::T_SRDLocation location_; protected: @@ -109,6 +109,9 @@ class A_Node bool replace( A_Node const& node , T_OwnPtr< A_Node >& replacement ) noexcept; + + void setParent( A_Node& newParent ) noexcept + { parent_ = &newParent; } }; // 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 { return dynamic_cast< A_InstructionNode& >( *children_[ index ] ); } + + void replaceMultiple( + A_InstructionNode& instruction , + T_InstrListNode* replacement ) noexcept; }; template< diff --git a/c-opopt.cc b/c-opopt.cc index 4825446..b7355c3 100644 --- a/c-opopt.cc +++ b/c-opopt.cc @@ -497,10 +497,12 @@ void T_OptData::buildControlFlowGraph( return; } numberInstructions( program ); + M_LOGSTR_( "Building control flow graph" , 4 ); // Keep the old array, we'll reuse its contents T_Array< P_CtrlFlowNode > old{ std::move( ctrlFlowGraph ) }; - M_LOGSTR_( "Building control flow graph" , 4 ); + callSites.clear( ); + cfgFunctions.clear( ); // Create special nodes M_ADDNEW_( ); @@ -512,7 +514,6 @@ void T_OptData::buildControlFlowGraph( // Generate control flow graph for each function T_BCFGStack_ stack; T_Optional< uint32_t > cNode{ }; - callSites.clear( ); visitor.visit( program.root , [&]( A_Node& node , const bool exit ) { return BCFGVisitor_( node , exit , *this , stack , cNode , old ); @@ -1568,54 +1569,112 @@ bool opopt::PropagateConstants( /*= DEAD CODE REMOVAL ========================================================*/ +namespace { + +struct T_RDCConstCond_ +{ + T_CondInstrNode* node; + int64_t value; +}; +using T_RDCConstCondList_ = T_AutoArray< T_RDCConstCond_ , 16 >; + +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 ); + } + + auto& cn{ dynamic_cast< T_CondInstrNode& >( node ) }; + auto const& ce{ cn.expression( ).expression( ) }; + if ( ce.type( ) == A_Node::EXPR_CONST ) { + const int64_t ccv{ ( (T_ConstantExprNode const&) ce ).intValue( ) }; + constConds.add( T_RDCConstCond_{ &cn , ccv } ); + 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; + } + + const auto ncc{ constConds.size( ) }; + for ( auto i = 0u ; i < ncc ; i ++ ) { + auto const& cc{ constConds[ i ] }; + auto& cn{ *cc.node }; + T_InstrListNode* replacement; + oData.logger( [&](){ + T_StringBuilder sb; + sb << "......... Conditional with constant argument at " + << cn.location( ); + return sb; + } , 4 ); + if ( cn.hasCase( cc.value ) ) { + 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( ) ) { + replacement = &cn.defaultCase( ).instructions( ); + oData.logger( [&](){ + T_StringBuilder sb; + sb << "Will replace with default case (" + << replacement->location( ) << ")"; + return sb; + } , 5 ); + } else { + M_LOGSTR_( "Will delete whole instruction" , 5 ); + replacement = nullptr; + } + ( (T_InstrListNode&) cn.parent( ) ).replaceMultiple( cn , replacement ); + } + + oData.state = {}; + return true; +} + +} // namespace + +/*----------------------------------------------------------------------------*/ bool opopt::RemoveDeadCode( T_OpsParserOutput& program , T_OptData& oData ) noexcept { - oData.buildUseDefineChains( program ); +// oData.buildUseDefineChains( program ); M_LOGSTR_( "... Eliminating dead code" , 2 ); - struct T_ConstCond_ { - T_CondInstrNode* node; - int64_t value; - }; - T_AutoArray< T_ConstCond_ , 16 > constConds; - oData.visitor.visit( program.root , [&]( A_Node& node , const bool exit ) { - const auto nt{ node.type( ) }; + 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 ( !exit && nt == A_Node::OP_COND ) { - auto& cn{ dynamic_cast< T_CondInstrNode& >( node ) }; - auto const& ce{ cn.expression( ).expression( ) }; - if ( ce.type( ) == A_Node::EXPR_CONST ) { - const int64_t ccv{ ( (T_ConstantExprNode const&) ce ).intValue( ) }; - constConds.add( T_ConstCond_{ &cn , ccv } ); - return false; - } - } - - return !dynamic_cast< A_ExpressionNode* >( &node ); - } ); - - if ( constConds.size( ) ) { - const auto ncc{ constConds.size( ) }; - for ( auto i = 0u ; i < ncc ; i ++ ) { - auto const& cc{ constConds[ i ] }; - auto& cn{ *cc.node }; - T_InstrListNode* replacement; - printf( "IF (CNST: %ld)!!!\n" , cc.value ); - if ( cn.hasCase( cc.value ) ) { - printf( "Will replace with case\n" ); - replacement = &cn.getCase( cc.value ).instructions( ); - } else if ( cn.hasDefaultCase( ) ) { - printf( "Will replace with default\n" ); - replacement = &cn.defaultCase( ).instructions( ); - } else { - printf( "DELETE! DELETE! DELETE!\n" ); - replacement = nullptr; - } - } + if ( didStuff ) { + M_LOGSTR_( "...... Dead code removed" , 3 ); + } else { + M_LOGSTR_( "...... No dead code found" , 3 ); } - - return false; + return didStuff; }