Optimizer - Determine order for call inlining

This commit is contained in:
Emmanuel BENOîT 2017-12-17 17:27:23 +01:00
parent 94b01e62b4
commit 1a6509814e

View file

@ -1854,6 +1854,20 @@ bool opopt::InlineFunctions(
M_LOGSTR_( "... Inlining functions" , 3 ); M_LOGSTR_( "... Inlining functions" , 3 );
// Find functions that can be inlined // Find functions that can be inlined
struct T_InlineFunction_ {
T_String target;
T_CallInstrNode* callInstrNode;
T_InlineFunction_(
T_String target ,
T_CallInstrNode* const call ) noexcept
: target( std::move( target ) ) ,
callInstrNode( call )
{ }
};
T_KeyValueTable< T_String , T_InlineFunction_ > inlineFunctions;
T_KeyValueTable< T_String , uint32_t > 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 };
@ -1882,11 +1896,11 @@ bool opopt::InlineFunctions(
assert( callNode.instructions ); assert( callNode.instructions );
const uint32_t callInstrIdx{ callNode.instructions->first const uint32_t callInstrIdx{ callNode.instructions->first
+ callNode.instructions->count - 1 }; + callNode.instructions->count - 1 };
auto const* const instr{ oData.instructions[ callInstrIdx ].node }; auto* const instr{ oData.instructions[ callInstrIdx ].node };
assert( instr && dynamic_cast< T_CallInstrNode const* >( instr ) ); assert( instr && dynamic_cast< T_CallInstrNode* >( instr ) );
// Check call arguments // Check call arguments
auto const& cInstr{ dynamic_cast< T_CallInstrNode const& >( *instr ) }; auto& cInstr{ dynamic_cast< T_CallInstrNode& >( *instr ) };
bool ok{ true }; bool ok{ true };
for ( auto i = 0u ; i < cInstr.size( ) && ok ; i ++ ) { for ( auto i = 0u ; i < cInstr.size( ) && ok ; i ++ ) {
auto const& arg{ cInstr.argument( i ) }; auto const& arg{ cInstr.argument( i ) };
@ -1898,16 +1912,58 @@ bool opopt::InlineFunctions(
} }
// Add to inlineable functions list // Add to inlineable functions list
// TODO auto const& caller{ program.root.function( callerId ).name( ) };
auto const& callee{ program.root.function( calleeId ).name( ) };
inlineFunctions.add( callee , T_InlineFunction_{
caller , &cInstr } );
auto* const callerCount{ inlineTargets.get( caller ) };
if ( callerCount ) {
(*callerCount) ++;
} else {
inlineTargets.add( caller , 1u );
}
oData.logger( [&](){ oData.logger( [&](){
T_StringBuilder sb; T_StringBuilder sb;
sb << "Will inline function " sb << "Will inline function " << callee
<< program.root.function( calleeId ).name( ); << " into " << caller;
return sb; return sb;
} , 4 ); } , 4 );
} }
if ( inlineFunctions.size( ) == 0 ) {
return false;
}
// Order inline-able functions // Order inline-able functions
T_AutoArray< uint32_t , 32 > ordered;
ordered.ensureCapacity( inlineFunctions.size( ) );
uint32_t index{ 0 };
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& tCount{ *inlineTargets.get( ifd.target ) };
tCount --;
if ( tCount == 0 ) {
inlineTargets.remove( ifd.target );
}
}
index = ( index + 1 ) % inlineFunctions.size( );
}
oData.logger( [&](){
T_StringBuilder sb;
sb << "Inlining order: ";
for ( auto i = 0u ; i < ordered.size( ) ; i ++ ) {
if ( i > 0 ) {
sb << ", ";
}
sb << inlineFunctions.keys( )[ ordered[ i ] ];
}
return sb;
} , 5 );
// Compute extra locals required // Compute extra locals required
// Merge (bottom to top) // Merge (bottom to top)