diff --git a/c-opopt.cc b/c-opopt.cc index 55201b7..e115f9c 100644 --- a/c-opopt.cc +++ b/c-opopt.cc @@ -1853,21 +1853,29 @@ bool opopt::InlineFunctions( oData.buildControlFlowGraph( program ); M_LOGSTR_( "... Inlining functions" , 3 ); - // Find functions that can be inlined + // Inline function data struct T_InlineFunction_ { T_String target; T_CallInstrNode* callInstrNode; + uint32_t fnIndex; T_InlineFunction_( T_String target , - T_CallInstrNode* const call ) noexcept - : target( std::move( target ) ) , - callInstrNode( call ) + T_CallInstrNode* const call , + const uint32_t fnIndex ) noexcept + : 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 , uint32_t > inlineTargets; + T_KeyValueTable< T_String , T_InlineTarget_ > inlineTargets; auto const& cfg{ oData.ctrlFlowGraph }; for ( auto it = cfg.begin( ) ; it != cfg.end( ) ; it ++ ) { auto const& node{ **it }; @@ -1915,12 +1923,12 @@ bool opopt::InlineFunctions( auto const& caller{ program.root.function( callerId ).name( ) }; auto const& callee{ program.root.function( calleeId ).name( ) }; inlineFunctions.add( callee , T_InlineFunction_{ - caller , &cInstr } ); + caller , &cInstr , calleeId } ); auto* const callerCount{ inlineTargets.get( caller ) }; if ( callerCount ) { - (*callerCount) ++; + callerCount->count ++; } else { - inlineTargets.add( caller , 1u ); + inlineTargets.add( caller , T_InlineTarget_{} ); } oData.logger( [&](){ @@ -1939,16 +1947,11 @@ bool opopt::InlineFunctions( 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 ) ) ) { + auto const& ifd{ inlineFunctions.values( )[ index ] }; + auto const* const ifr{ inlineTargets.get( inlineFunctions.keys( )[ index ] ) }; + if ( !( ordered.contains( index ) || ( ifr && ifr->count > 0 ) ) ) { ordered.add( index ); - - auto const& ifd{ inlineFunctions.values( )[ index ] }; - auto& tCount{ *inlineTargets.get( ifd.target ) }; - tCount --; - if ( tCount == 0 ) { - inlineTargets.remove( ifd.target ); - } + inlineTargets.get( ifd.target )->count --; } index = ( index + 1 ) % inlineFunctions.size( ); } @@ -1965,6 +1968,26 @@ bool opopt::InlineFunctions( } , 5 ); // 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) return false;