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 ) )
|
<< M_BCL_TOGGLE_( constantPropagation ) )
|
||||||
<< ( Rule( ) << "dead-code-elimination" << Enum( "on-off" )
|
<< ( Rule( ) << "dead-code-elimination" << Enum( "on-off" )
|
||||||
<< M_BCL_TOGGLE_( deadCodeElimination ) )
|
<< M_BCL_TOGGLE_( deadCodeElimination ) )
|
||||||
|
<< ( Rule( ) << "function-inlining" << Enum( "on-off" )
|
||||||
|
<< M_BCL_TOGGLE_( inlineFunctions ) )
|
||||||
;
|
;
|
||||||
|
|
||||||
defs.context( "opt-cf" )
|
defs.context( "opt-cf" )
|
||||||
|
|
|
@ -34,6 +34,10 @@ struct T_BuildConfiguration
|
||||||
// Dead code elimination -----------------------------------------------
|
// Dead code elimination -----------------------------------------------
|
||||||
|
|
||||||
bool deadCodeElimination{ false };
|
bool deadCodeElimination{ false };
|
||||||
|
|
||||||
|
// Function inlining ---------------------------------------------------
|
||||||
|
|
||||||
|
bool inlineFunctions{ false };
|
||||||
};
|
};
|
||||||
|
|
||||||
// Table of avaiable build configurations
|
// Table of avaiable build configurations
|
||||||
|
|
90
c-opopt.cc
90
c-opopt.cc
|
@ -1823,3 +1823,93 @@ bool opopt::RemoveDeadCode(
|
||||||
}
|
}
|
||||||
return didStuff;
|
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;
|
T_OptData& optData ) noexcept;
|
||||||
|
|
||||||
// Attempt to remove blocks of code that will not be executed because of
|
// Attempt to remove blocks of code that will not be executed because of
|
||||||
// constant conditions.
|
// constant conditions, dead stores, etc...
|
||||||
//
|
//
|
||||||
bool RemoveDeadCode(
|
bool RemoveDeadCode(
|
||||||
T_OpsParserOutput& program ,
|
T_OpsParserOutput& program ,
|
||||||
T_OptData& optData ) noexcept;
|
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
|
} // namespace opopt
|
||||||
|
|
15
m-builder.cc
15
m-builder.cc
|
@ -249,19 +249,22 @@ int main( int argc , char** argv )
|
||||||
od.curves = &p.curves;
|
od.curves = &p.curves;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool doneStuff;
|
bool didStuff;
|
||||||
do {
|
do {
|
||||||
doneStuff = false;
|
didStuff = false;
|
||||||
if ( cfg.constantFolding && opopt::FoldConstants( *parsed , od ) ) {
|
if ( cfg.constantFolding && opopt::FoldConstants( *parsed , od ) ) {
|
||||||
doneStuff = true;
|
didStuff = true;
|
||||||
}
|
}
|
||||||
if ( cfg.constantPropagation && opopt::PropagateConstants( *parsed , od ) ) {
|
if ( cfg.constantPropagation && opopt::PropagateConstants( *parsed , od ) ) {
|
||||||
doneStuff = true;
|
didStuff = true;
|
||||||
}
|
}
|
||||||
if ( cfg.deadCodeElimination && opopt::RemoveDeadCode( *parsed , od ) ) {
|
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
|
// Compile
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
)
|
)
|
||||||
(constant-propagation on)
|
(constant-propagation on)
|
||||||
(dead-code-elimination on)
|
(dead-code-elimination on)
|
||||||
|
(function-inlining on)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -362,9 +362,9 @@
|
||||||
|
|
||||||
(fn bloom-downsample (target level)
|
(fn bloom-downsample (target level)
|
||||||
(locals m w h)
|
(locals m w h)
|
||||||
(set m (inv (pow 2 $level)))
|
(set m (pow 2 $level))
|
||||||
(set w (mul $vp-width $m))
|
(set w (div $vp-width $m))
|
||||||
(set h (mul $vp-height $m))
|
(set h (div $vp-height $m))
|
||||||
|
|
||||||
(use-pipeline pl-bloom-downsample)
|
(use-pipeline pl-bloom-downsample)
|
||||||
(use-framebuffer target)
|
(use-framebuffer target)
|
||||||
|
|
Loading…
Reference in a new issue