Optimizer - Remove dead branches
This commit is contained in:
parent
08e486a57c
commit
ab279857fa
3 changed files with 154 additions and 44 deletions
44
c-opast.cc
44
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 ======================================================*/
|
||||
|
||||
|
|
|
@ -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<
|
||||
|
|
145
c-opopt.cc
145
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 <anon>
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue