Optimizer - Finished function inlining

This commit is contained in:
Emmanuel BENOîT 2017-12-23 17:18:29 +01:00
parent 2c636fb7b5
commit d3b1883693
3 changed files with 260 additions and 4 deletions

View file

@ -474,7 +474,7 @@ void T_InstrListNode::replaceMultiple(
children_.addNew( );
}
const auto newSize{ children_.size( ) };
const auto nMove{ oldSize + 1 - index };
const auto nMove{ rep.size( ) > 1 ? ( oldSize - index ) : 0 };
for ( auto i = 1u ; i < nMove ; i ++ ) {
children_[ newSize - i ] = std::move(
children_[ oldSize - i ] );
@ -486,6 +486,8 @@ void T_InstrListNode::replaceMultiple(
rep.children_[ i ] );
children_[ index + i ]->setParent( *this );
}
rep.children_.clear( );
} else {
children_.remove( index );
}

View file

@ -622,6 +622,9 @@ class T_SetInstrNode : public A_InstructionNode
ebcl::T_SRDLocation const& idLocation( ) const noexcept
{ return idLocation_; }
void id( T_String const& nid ) noexcept
{ id_ = nid; }
void setExpression( P_ExpressionNode expression ) noexcept
{
if ( children_.size( ) ) {
@ -707,6 +710,13 @@ class T_FramebufferInstrNode : public A_ResourceDefInstrNode
T_ArgumentNode* lod( ) const noexcept
{ return (T_ArgumentNode*) ( children_.size( )
? child( 0 ).get( ) : nullptr ); }
void id( T_String const& nid ,
ebcl::T_SRDLocation const& loc ) noexcept
{
id_ = nid;
location( ) = loc;
}
};
private:
@ -802,6 +812,14 @@ class T_PipelineInstrNode : public A_ResourceDefInstrNode
{ return pids_[ index ]; }
ebcl::T_SRDLocation const& pLocation( const uint32_t index ) const noexcept
{ return pidLocations_[ index ]; }
void program( const uint32_t index ,
T_String const& id ,
ebcl::T_SRDLocation const& location ) noexcept
{
pids_[ index ] = id;
pidLocations_[ index ] = location;
}
};
// Program loader instruction
@ -1119,6 +1137,9 @@ class T_UniformsInstrNode : public A_InstructionNode
{ return progId_; }
ebcl::T_SRDLocation const& progIdLocation( ) const noexcept
{ return progIdLocation_; }
void progId( T_String const& id ,
ebcl::T_SRDLocation const& location ) noexcept
{ progId_ = id; progIdLocation_ = location; }
uint32_t uloc( ) const noexcept
{ return uloc_; }
@ -1171,6 +1192,9 @@ class T_UseInstrNode : public A_InstructionNode
{ return id_; }
ebcl::T_SRDLocation const& idLocation( ) const noexcept
{ return idLocation_; }
void id( T_String const& nid ,
ebcl::T_SRDLocation const& location ) noexcept
{ id_ = nid; idLocation_ = location; }
};
// Texture/sampler use instructions
@ -1203,6 +1227,9 @@ class T_UseTextureInstrNode : public T_UseInstrNode
{ return samplerId_; }
ebcl::T_SRDLocation const& samplerIdLocation( ) const noexcept
{ return samplerIdLocation_; }
void samplerId( T_String const& id ,
ebcl::T_SRDLocation const& location ) noexcept
{ samplerId_ = id; samplerIdLocation_ = location; }
};
// Viewport instruction

View file

@ -1858,6 +1858,8 @@ bool opopt::InlineFunctions(
T_String target;
T_CallInstrNode* callInstrNode;
uint32_t fnIndex;
uint32_t nArgs{ 0 };
uint32_t nLocals{ 0 };
T_InlineFunction_(
T_String target ,
@ -1871,6 +1873,7 @@ bool opopt::InlineFunctions(
struct T_InlineTarget_ {
uint32_t count{ 1 };
uint32_t extraLocals{ 0 };
T_AutoArray< T_String , 16 > elNames;
};
// Find functions that can be inlined
@ -1970,11 +1973,12 @@ bool opopt::InlineFunctions(
// Compute extra locals required
const auto nInlines{ ordered.size( ) };
for ( auto i = 0u ; i < nInlines ; i ++ ) {
auto const& ifd{ inlineFunctions.values( )[ ordered[ i ] ] };
auto& 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 ) ) ) {
ifd.nArgs ++;
nLocals --;
}
}
@ -1984,11 +1988,234 @@ bool opopt::InlineFunctions(
nLocals += asTarget->extraLocals;
}
ifd.nLocals = nLocals;
auto* target{ inlineTargets.get( ifd.target ) };
target->extraLocals = std::max( target->extraLocals , nLocals );
}
// Merge (bottom to top)
// Add extra locals
const auto nTargets{ inlineTargets.size( ) };
T_StringBuilder idsb;
for ( auto i = 0u ; i < nTargets ; i ++ ) {
auto& itd{ inlineTargets.values( )[ i ] };
auto& fn{ program.root.function( inlineTargets.keys( )[ i ] ) };
for ( auto j = 0u , c = 0u ; c < itd.extraLocals ; j ++ ) {
idsb.clear( ) << "*inline*" << j;
T_String id{ idsb };
if ( !fn.hasLocal( id ) ) {
fn.addLocalVariable( id , T_SRDLocation{} );
fn.setLocalType( fn.locals( ) - 1 ,
opast::E_DataType::VARIABLE );
itd.elNames.add( std::move( id ) );
c ++;
}
}
}
return false;
// Merge (bottom to top)
for ( auto i = 0u ; i < nInlines ; i ++ ) {
auto const& ifd{ inlineFunctions.values( )[ i ] };
auto const& itd{ *inlineTargets.get( ifd.target ) };
auto& src{ program.root.function( ifd.fnIndex ) };
auto& call{ *ifd.callInstrNode };
oData.logger( [&]() {
T_StringBuilder sb;
sb << "Inlining function " << src.name( );
return sb;
} , 5 );
// Replace arguments and locals
oData.visitor.visit( src.instructions( ) , [&]( A_Node& node , const bool exit ) {
if ( !exit ) {
return true;
}
switch ( node.type( ) ) {
default: break;
case A_Node::EXPR_ID: {
auto const& id{ (T_IdentifierExprNode&) node };
if ( !src.hasLocal( id.id( ) ) ) {
break;
}
T_OwnPtr< A_Node > nv;
if ( src.isArgument( id.id( ) ) ) {
const auto argIndex{ src.getLocalIndex( id.id( ) ) };
auto const& callArg{ call.argument( argIndex ) };
auto const& caValue{ callArg.expression( ) };
if ( caValue.type( ) == A_Node::EXPR_CONST ) {
nv = NewOwned< T_ConstantExprNode >(
node.parent( ) ,
( (T_ConstantExprNode&) caValue ).floatValue( ) );
} else {
nv = NewOwned< T_IdentifierExprNode >(
node.parent( ) ,
( (T_IdentifierExprNode&) caValue ).id( ) );
}
} else {
nv = NewOwned< T_IdentifierExprNode >(
node.parent( ) ,
itd.elNames[ src.getLocalIndex( id.id( ) ) - ifd.nArgs ] );
}
oData.logger( [&]() {
T_StringBuilder sb;
sb << "Replacing identifier " << id.id( )
<< " at " << id.location( )
<< " with ";
if ( nv->type( ) == A_Node::EXPR_ID ) {
sb << "identifier " << ((T_IdentifierExprNode&)*nv).id( );
} else {
sb << "constant " << ((T_ConstantExprNode&)*nv).floatValue( );
}
return sb;
} , 6 );
node.parent( ).replace( node , nv );
break;
}
case A_Node::OP_UNIFORMS: {
auto& n{ (T_UniformsInstrNode&) node };
if ( src.isArgument( n.progId( ) ) ) {
const auto argIndex{ src.getLocalIndex( n.progId( ) ) };
auto const& callArg{ call.argument( argIndex ) };
auto const& caValue{ callArg.expression( ) };
assert( caValue.type( ) == A_Node::EXPR_ID );
auto const& repId{ ( (T_IdentifierExprNode&) caValue ).id( ) };
oData.logger( [&]() {
T_StringBuilder sb;
sb << "Replacing identifier " << n.progId( )
<< " at " << n.progIdLocation( )
<< " with identifier " << repId;
return sb;
} , 6 );
n.progId( repId , caValue.location( ) );
}
break;
}
case A_Node::OP_USE_TEXTURE: {
auto& n{ (T_UseTextureInstrNode&) node };
if ( src.isArgument( n.samplerId( ) ) ) {
const auto argIndex{ src.getLocalIndex( n.samplerId( ) ) };
auto const& callArg{ call.argument( argIndex ) };
auto const& caValue{ callArg.expression( ) };
assert( caValue.type( ) == A_Node::EXPR_ID );
auto const& repId{ ( (T_IdentifierExprNode&) caValue ).id( ) };
oData.logger( [&]() {
T_StringBuilder sb;
sb << "Replacing identifier " << n.samplerId( )
<< " at " << n.samplerIdLocation( )
<< " with identifier " << repId;
return sb;
} , 6 );
n.samplerId( repId , caValue.location( ) );
}
} // fallthrough
case A_Node::OP_USE_PROGRAM:
case A_Node::OP_USE_PIPELINE:
case A_Node::OP_USE_FRAMEBUFFER: {
auto& n{ (T_UseInstrNode&) node };
if ( src.isArgument( n.id( ) ) ) {
const auto argIndex{ src.getLocalIndex( n.id( ) ) };
auto const& callArg{ call.argument( argIndex ) };
auto const& caValue{ callArg.expression( ) };
assert( caValue.type( ) == A_Node::EXPR_ID );
auto const& repId{ ( (T_IdentifierExprNode&) caValue ).id( ) };
oData.logger( [&]() {
T_StringBuilder sb;
sb << "Replacing identifier " << n.id( )
<< " at " << n.idLocation( )
<< " with identifier " << repId;
return sb;
} , 6 );
n.id( repId , caValue.location( ) );
}
break;
}
case A_Node::OP_PIPELINE: {
auto& n{ (T_PipelineInstrNode&) node };
const auto np{ n.size( ) };
for ( auto i = 0u ; i < np ; i ++ ) {
if ( src.isArgument( n.program( i ) ) ) {
const auto argIndex{ src.getLocalIndex( n.program( i ) ) };
auto const& callArg{ call.argument( argIndex ) };
auto const& caValue{ callArg.expression( ) };
assert( caValue.type( ) == A_Node::EXPR_ID );
auto const& repId{ ( (T_IdentifierExprNode&) caValue ).id( ) };
oData.logger( [&]() {
T_StringBuilder sb;
sb << "Replacing identifier " << n.program( i )
<< " at " << n.pLocation( i )
<< " with identifier " << repId;
return sb;
} , 6 );
n.program( i , repId , caValue.location( ) );
}
}
break;
}
case A_Node::TN_FBATT: {
auto& n{ (T_FramebufferInstrNode::T_Attachment&) node };
if ( src.isArgument( n.id( ) ) ) {
const auto argIndex{ src.getLocalIndex( n.id( ) ) };
auto const& callArg{ call.argument( argIndex ) };
auto const& caValue{ callArg.expression( ) };
assert( caValue.type( ) == A_Node::EXPR_ID );
auto const& repId{ ( (T_IdentifierExprNode&) caValue ).id( ) };
oData.logger( [&]() {
T_StringBuilder sb;
sb << "Replacing identifier " << n.id( )
<< " at " << n.location( )
<< " with identifier " << repId;
return sb;
} , 6 );
n.id( repId , caValue.location( ) );
}
break;
}
case A_Node::OP_SET: {
auto& n{ (T_SetInstrNode&) node };
if ( !src.hasLocal( n.id( ) ) ) {
break;
}
auto const& nid{
itd.elNames[ src.getLocalIndex( n.id( ) ) - ifd.nArgs ]
};
oData.logger( [&]() {
T_StringBuilder sb;
sb << "Replacing identifier " << n.id( )
<< " at " << n.location( )
<< " with identifier " << nid;
return sb;
} , 6 );
n.id( nid );
break;
}
}
return true;
} );
((T_InstrListNode&) call.parent( )).replaceMultiple(
call , &src.instructions( ) );
}
T_AutoArray< T_String , 32 > iffns;
iffns.ensureCapacity( nInlines );
for ( auto i = 0u ; i < nInlines ; i ++ ) {
auto const& ifd{ inlineFunctions.values( )[ i ] };
iffns.add( program.root.function( ifd.fnIndex ).name( ) );
}
for ( auto i = 0u ; i < nInlines ; i ++ ) {
program.root.removeFunction( iffns[ i ] );
}
oData.state = {};
return true;
}