Optimizer - Count required extra locals for function inlining

This commit is contained in:
Emmanuel BENOîT 2017-12-17 19:02:00 +01:00
parent 1a6509814e
commit 2c636fb7b5

View file

@ -1853,21 +1853,29 @@ bool opopt::InlineFunctions(
oData.buildControlFlowGraph( program ); oData.buildControlFlowGraph( program );
M_LOGSTR_( "... Inlining functions" , 3 ); M_LOGSTR_( "... Inlining functions" , 3 );
// Find functions that can be inlined // Inline function data
struct T_InlineFunction_ { struct T_InlineFunction_ {
T_String target; T_String target;
T_CallInstrNode* callInstrNode; T_CallInstrNode* callInstrNode;
uint32_t fnIndex;
T_InlineFunction_( T_InlineFunction_(
T_String target , T_String target ,
T_CallInstrNode* const call ) noexcept T_CallInstrNode* const call ,
: target( std::move( target ) ) , const uint32_t fnIndex ) noexcept
callInstrNode( call ) : target{ std::move( target ) } ,
callInstrNode{ call } , fnIndex{ fnIndex }
{ } { }
}; };
// Inlining target function data
struct T_InlineTarget_ {
uint32_t count{ 1 };
uint32_t extraLocals{ 0 };
};
// Find functions that can be inlined
T_KeyValueTable< T_String , T_InlineFunction_ > inlineFunctions; T_KeyValueTable< T_String , T_InlineFunction_ > inlineFunctions;
T_KeyValueTable< T_String , uint32_t > inlineTargets; T_KeyValueTable< T_String , T_InlineTarget_ > inlineTargets;
auto const& cfg{ oData.ctrlFlowGraph }; auto const& cfg{ oData.ctrlFlowGraph };
for ( auto it = cfg.begin( ) ; it != cfg.end( ) ; it ++ ) { for ( auto it = cfg.begin( ) ; it != cfg.end( ) ; it ++ ) {
auto const& node{ **it }; auto const& node{ **it };
@ -1915,12 +1923,12 @@ bool opopt::InlineFunctions(
auto const& caller{ program.root.function( callerId ).name( ) }; auto const& caller{ program.root.function( callerId ).name( ) };
auto const& callee{ program.root.function( calleeId ).name( ) }; auto const& callee{ program.root.function( calleeId ).name( ) };
inlineFunctions.add( callee , T_InlineFunction_{ inlineFunctions.add( callee , T_InlineFunction_{
caller , &cInstr } ); caller , &cInstr , calleeId } );
auto* const callerCount{ inlineTargets.get( caller ) }; auto* const callerCount{ inlineTargets.get( caller ) };
if ( callerCount ) { if ( callerCount ) {
(*callerCount) ++; callerCount->count ++;
} else { } else {
inlineTargets.add( caller , 1u ); inlineTargets.add( caller , T_InlineTarget_{} );
} }
oData.logger( [&](){ oData.logger( [&](){
@ -1939,16 +1947,11 @@ bool opopt::InlineFunctions(
ordered.ensureCapacity( inlineFunctions.size( ) ); ordered.ensureCapacity( inlineFunctions.size( ) );
uint32_t index{ 0 }; uint32_t index{ 0 };
while ( inlineFunctions.size( ) > ordered.size( ) ) { while ( inlineFunctions.size( ) > ordered.size( ) ) {
auto const& fn{ inlineFunctions.keys( )[ index ] };
if ( !( ordered.contains( index ) || inlineTargets.contains( fn ) ) ) {
ordered.add( index );
auto const& ifd{ inlineFunctions.values( )[ index ] }; auto const& ifd{ inlineFunctions.values( )[ index ] };
auto& tCount{ *inlineTargets.get( ifd.target ) }; auto const* const ifr{ inlineTargets.get( inlineFunctions.keys( )[ index ] ) };
tCount --; if ( !( ordered.contains( index ) || ( ifr && ifr->count > 0 ) ) ) {
if ( tCount == 0 ) { ordered.add( index );
inlineTargets.remove( ifd.target ); inlineTargets.get( ifd.target )->count --;
}
} }
index = ( index + 1 ) % inlineFunctions.size( ); index = ( index + 1 ) % inlineFunctions.size( );
} }
@ -1965,6 +1968,26 @@ bool opopt::InlineFunctions(
} , 5 ); } , 5 );
// Compute extra locals required // Compute extra locals required
const auto nInlines{ ordered.size( ) };
for ( auto i = 0u ; i < nInlines ; i ++ ) {
auto const& ifd{ inlineFunctions.values( )[ ordered[ i ] ] };
auto const& fn{ program.root.function( ifd.fnIndex ) };
uint32_t nLocals{ fn.locals( ) };
for ( auto j = 0u ; j < fn.locals( ) ; j ++ ) {
if ( fn.isArgument( fn.getLocalName( j ) ) ) {
nLocals --;
}
}
auto const* const asTarget{ inlineTargets.get( fn.name( ) ) };
if ( asTarget ) {
nLocals += asTarget->extraLocals;
}
auto* target{ inlineTargets.get( ifd.target ) };
target->extraLocals = std::max( target->extraLocals , nLocals );
}
// Merge (bottom to top) // Merge (bottom to top)
return false; return false;