Optimizer - Started work on function inlining
For now: * Option that triggers inlining * Compute list of inline-able functions
This commit is contained in:
parent
fd84c3cae3
commit
94b01e62b4
7 changed files with 117 additions and 10 deletions
|
@ -140,6 +140,8 @@ T_SRDParserConfig BCLInitDefinitions_( ) noexcept
|
|||
<< M_BCL_TOGGLE_( constantPropagation ) )
|
||||
<< ( Rule( ) << "dead-code-elimination" << Enum( "on-off" )
|
||||
<< M_BCL_TOGGLE_( deadCodeElimination ) )
|
||||
<< ( Rule( ) << "function-inlining" << Enum( "on-off" )
|
||||
<< M_BCL_TOGGLE_( inlineFunctions ) )
|
||||
;
|
||||
|
||||
defs.context( "opt-cf" )
|
||||
|
|
|
@ -34,6 +34,10 @@ struct T_BuildConfiguration
|
|||
// Dead code elimination -----------------------------------------------
|
||||
|
||||
bool deadCodeElimination{ false };
|
||||
|
||||
// Function inlining ---------------------------------------------------
|
||||
|
||||
bool inlineFunctions{ false };
|
||||
};
|
||||
|
||||
// Table of avaiable build configurations
|
||||
|
|
90
c-opopt.cc
90
c-opopt.cc
|
@ -1823,3 +1823,93 @@ bool opopt::RemoveDeadCode(
|
|||
}
|
||||
return didStuff;
|
||||
}
|
||||
|
||||
|
||||
/*= FUNCTION INLINING ========================================================*/
|
||||
namespace {
|
||||
|
||||
uint32_t IFFindFunctionForNode_(
|
||||
T_OptData const& data ,
|
||||
const uint32_t cfgNode
|
||||
) noexcept
|
||||
{
|
||||
const auto ncf{ data.cfgFunctions.size( ) };
|
||||
for ( auto i = 0u ; i < ncf ; i ++ ) {
|
||||
auto const& block{ data.cfgFunctions[ i ] };
|
||||
if ( block.first <= cfgNode && block.first + block.count > cfgNode ) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return T_HashIndex::INVALID_INDEX;
|
||||
}
|
||||
|
||||
} // namespace <anon>
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
bool opopt::InlineFunctions(
|
||||
T_OpsParserOutput& program ,
|
||||
T_OptData& oData ) noexcept
|
||||
{
|
||||
oData.buildControlFlowGraph( program );
|
||||
M_LOGSTR_( "... Inlining functions" , 3 );
|
||||
|
||||
// Find functions that can be inlined
|
||||
auto const& cfg{ oData.ctrlFlowGraph };
|
||||
for ( auto it = cfg.begin( ) ; it != cfg.end( ) ; it ++ ) {
|
||||
auto const& node{ **it };
|
||||
|
||||
// We need a single inbound edge, with CALL type
|
||||
if ( node.inbound.size( ) != 1 ) {
|
||||
continue;
|
||||
}
|
||||
if ( node.inbound[ 0 ].type != T_OptData::T_CtrlFlowEdge::CALL ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the function we're in and the function the call came from
|
||||
const auto calleeId{ IFFindFunctionForNode_(
|
||||
oData , it.pos( ) ) };
|
||||
const auto callerId{ IFFindFunctionForNode_(
|
||||
oData , node.inbound[ 0 ].target ) };
|
||||
|
||||
// Ignore recursive functions or fake calls to *init*/*frame*
|
||||
if ( callerId == calleeId || callerId == T_HashIndex::INVALID_INDEX ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find corresponding call instruction
|
||||
auto const& callNode{ *oData.ctrlFlowGraph[ node.inbound[ 0 ].target ] };
|
||||
assert( callNode.instructions );
|
||||
const uint32_t callInstrIdx{ callNode.instructions->first
|
||||
+ callNode.instructions->count - 1 };
|
||||
auto const* const instr{ oData.instructions[ callInstrIdx ].node };
|
||||
assert( instr && dynamic_cast< T_CallInstrNode const* >( instr ) );
|
||||
|
||||
// Check call arguments
|
||||
auto const& cInstr{ dynamic_cast< T_CallInstrNode const& >( *instr ) };
|
||||
bool ok{ true };
|
||||
for ( auto i = 0u ; i < cInstr.size( ) && ok ; i ++ ) {
|
||||
auto const& arg{ cInstr.argument( i ) };
|
||||
const auto aet{ arg.expression( ).type( ) };
|
||||
ok = ( aet == A_Node::EXPR_CONST || aet == A_Node::EXPR_ID );
|
||||
}
|
||||
if ( !ok ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add to inlineable functions list
|
||||
// TODO
|
||||
oData.logger( [&](){
|
||||
T_StringBuilder sb;
|
||||
sb << "Will inline function "
|
||||
<< program.root.function( calleeId ).name( );
|
||||
return sb;
|
||||
} , 4 );
|
||||
}
|
||||
|
||||
// Order inline-able functions
|
||||
// Compute extra locals required
|
||||
// Merge (bottom to top)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -217,11 +217,18 @@ bool PropagateConstants(
|
|||
T_OptData& optData ) noexcept;
|
||||
|
||||
// Attempt to remove blocks of code that will not be executed because of
|
||||
// constant conditions.
|
||||
// constant conditions, dead stores, etc...
|
||||
//
|
||||
bool RemoveDeadCode(
|
||||
T_OpsParserOutput& program ,
|
||||
T_OptData& optData ) noexcept;
|
||||
|
||||
// Attempt to inline functions that are only used once and which have simple
|
||||
// argument values (constants or identifiers).
|
||||
//
|
||||
bool InlineFunctions(
|
||||
T_OpsParserOutput& program ,
|
||||
T_OptData& optData ) noexcept;
|
||||
|
||||
|
||||
} // namespace opopt
|
||||
|
|
15
m-builder.cc
15
m-builder.cc
|
@ -249,19 +249,22 @@ int main( int argc , char** argv )
|
|||
od.curves = &p.curves;
|
||||
}
|
||||
|
||||
bool doneStuff;
|
||||
bool didStuff;
|
||||
do {
|
||||
doneStuff = false;
|
||||
didStuff = false;
|
||||
if ( cfg.constantFolding && opopt::FoldConstants( *parsed , od ) ) {
|
||||
doneStuff = true;
|
||||
didStuff = true;
|
||||
}
|
||||
if ( cfg.constantPropagation && opopt::PropagateConstants( *parsed , od ) ) {
|
||||
doneStuff = true;
|
||||
didStuff = true;
|
||||
}
|
||||
if ( cfg.deadCodeElimination && opopt::RemoveDeadCode( *parsed , od ) ) {
|
||||
doneStuff = true;
|
||||
didStuff = true;
|
||||
}
|
||||
} while ( doneStuff );
|
||||
if ( cfg.inlineFunctions && opopt::InlineFunctions( *parsed , od ) ) {
|
||||
didStuff = true;
|
||||
}
|
||||
} while ( didStuff );
|
||||
}
|
||||
|
||||
// Compile
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
)
|
||||
(constant-propagation on)
|
||||
(dead-code-elimination on)
|
||||
(function-inlining on)
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -362,9 +362,9 @@
|
|||
|
||||
(fn bloom-downsample (target level)
|
||||
(locals m w h)
|
||||
(set m (inv (pow 2 $level)))
|
||||
(set w (mul $vp-width $m))
|
||||
(set h (mul $vp-height $m))
|
||||
(set m (pow 2 $level))
|
||||
(set w (div $vp-width $m))
|
||||
(set h (div $vp-height $m))
|
||||
|
||||
(use-pipeline pl-bloom-downsample)
|
||||
(use-framebuffer target)
|
||||
|
|
Loading…
Reference in a new issue