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;
|
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 ======================================================*/
|
||||||
|
|
||||||
|
|
|
@ -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<
|
||||||
|
|
145
c-opopt.cc
145
c-opopt.cc
|
@ -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 {
|
||||||
|
|
||||||
|
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(
|
bool opopt::RemoveDeadCode(
|
||||||
T_OpsParserOutput& program ,
|
T_OpsParserOutput& program ,
|
||||||
T_OptData& oData ) noexcept
|
T_OptData& oData ) noexcept
|
||||||
{
|
{
|
||||||
oData.buildUseDefineChains( program );
|
// oData.buildUseDefineChains( program );
|
||||||
M_LOGSTR_( "... Eliminating dead code" , 2 );
|
M_LOGSTR_( "... Eliminating dead code" , 2 );
|
||||||
|
|
||||||
struct T_ConstCond_ {
|
bool didStuff{ false };
|
||||||
T_CondInstrNode* node;
|
// bool tryDeadStoresFirst{ oData.state & T_OptData::E_StateItem::UDCHAINS };
|
||||||
int64_t value;
|
bool didStuffThisTime;
|
||||||
};
|
do {
|
||||||
T_AutoArray< T_ConstCond_ , 16 > constConds;
|
didStuffThisTime = RDCConditionals_( program , oData );
|
||||||
oData.visitor.visit( program.root , [&]( A_Node& node , const bool exit ) {
|
didStuff = didStuff || didStuffThisTime;
|
||||||
const auto nt{ node.type( ) };
|
} while ( didStuffThisTime );
|
||||||
|
|
||||||
if ( !exit && nt == A_Node::OP_COND ) {
|
if ( didStuff ) {
|
||||||
auto& cn{ dynamic_cast< T_CondInstrNode& >( node ) };
|
M_LOGSTR_( "...... Dead code removed" , 3 );
|
||||||
auto const& ce{ cn.expression( ).expression( ) };
|
} else {
|
||||||
if ( ce.type( ) == A_Node::EXPR_CONST ) {
|
M_LOGSTR_( "...... No dead code found" , 3 );
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return didStuff;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue