Optimizer - UD chains - WORKING (fo'real, man)

Horrible, spaghettish, slow, memory hungry but WORKING implementation of
use/define chains!!!!
This commit is contained in:
Emmanuel BENOîT 2017-12-12 15:33:03 +01:00
parent cc519be077
commit 7e5d782d2f

View file

@ -761,6 +761,265 @@ void BUDCLink_(
} , LL2 ); } , LL2 );
} }
/*----------------------------------------------------------------------------*/
struct T_BUDCDefSet_
{
T_Set< uint32_t > set{ UseTag< ArrayBacked< 4 > >( ) };
T_AutoArray< uint8_t , 1 > bitmap;
explicit T_BUDCDefSet_( const uint32_t max ) noexcept
{
const auto nBytesRaw{ max >> 3 };
const auto nBytes{ nBytesRaw + ( ( max & 7 ) != 0 ? 1 : 0 ) };
for ( auto i = 0u ; i < nBytes ; i ++ ) {
bitmap.add( 0 );
}
}
void clear( ) noexcept
{
set.clear( );
for ( auto i = 0u ; i < bitmap.size( ) ; i ++ ) {
bitmap[ i ] = 0;
}
}
void add( const uint32_t item ) noexcept
{
const auto byte{ item >> 3 };
const auto bit{ item & 7 };
const auto mask{ 1 << bit };
if ( ( bitmap[ byte ] & mask ) == 0 ) {
bitmap[ byte ] |= mask;
set.add( item );
}
}
bool operator ==( T_BUDCDefSet_ const& other ) noexcept
{
if ( bitmap.size( ) != other.bitmap.size( ) ) {
return false;
}
for ( auto i = 0u ; i < bitmap.size( ) ; i ++ ) {
if ( bitmap[ i ] != other.bitmap[ i ] ) {
return false;
}
}
return true;
}
};
void BUDCWalkGraph_(
T_OptData& data ,
T_OptData::T_VarUseDefine& var ,
T_UDEPerInstr_& udPerInstr ,
T_Optional< uint32_t > fnIndex
) noexcept
{
T_Set< uint32_t > changed{ UseTag< ArrayBacked< 16 > >( ) }; // FIXME alloc
T_Array< T_BUDCDefSet_ > defines; // FIXME alloc
defines.resize( data.ctrlFlowGraph.size( ) , T_BUDCDefSet_{ 0 } );
data.logger( [&]() {
T_StringBuilder sb;
sb << "Walking graph for " << var.var.name << " (";
switch ( var.var.type ) {
case T_OptData::E_UDVarType::GLOBAL:
sb << "global";
break;
case T_OptData::E_UDVarType::ARGUMENT:
sb << "argument of " << var.var.owner;
break;
case T_OptData::E_UDVarType::LOCAL:
sb << "local variable of " << var.var.owner;
break;
}
sb << ')';
return sb;
} , LL1 );
auto const* const fn{ fnIndex
? &data.cfgFunctions[ *fnIndex ]
: nullptr };
auto const nFirst{ fn ? fn->first : 0u };
auto const nEnd{ fn ? ( fn->first + fn->count )
: data.ctrlFlowGraph.size( ) };
#if 0
data.logger( [=](){
T_StringBuilder sb{ "Nodes " };
sb << nFirst << " ... " << ( nEnd - 1 );;
return sb;
} , LL2 );
#endif
changed.add( nFirst );
for ( auto i = nEnd ; i > nFirst + 1 ; i -- ) {
changed.add( i - 1 );
}
while ( changed.size( ) ) {
const auto node{ changed[ 0 ] };
#if 0
data.logger( [=](){
T_StringBuilder sb{ "Checking node " };
sb << node;
return sb;
} , LL2 );
#endif
assert( node >= nFirst && node < nEnd );
auto const& cn{ *data.ctrlFlowGraph[ node ] };
changed.remove( node );
// Assemble the set of possible definitions at the start of
// the block.
T_BUDCDefSet_ sInput{ var.defines.size( ) };
const auto nIn{ cn.inbound.size( ) };
for ( auto i = 0u ; i < nIn ; i ++ ) {
auto const& ib{ cn.inbound[ i ] };
// Make sure the inbound link type is right (FLOW always
// is, BYPASS works in functions, CALL/RET at the global
// level)
if ( ib.type != ib.FLOW && (
( fnIndex && ib.type != ib.BYPASS )
|| ( !fnIndex && ib.type == ib.BYPASS ) ) ) {
continue;
}
// Get defines from node
auto const& sNode{ defines[ ib.target ] };
const auto nIbIn{ sNode.set.size( ) };
for ( auto j = 0u ; j < nIbIn ; j ++ ) {
sInput.add( sNode.set[ j ] );
}
}
if ( cn.instructions ) {
// Check for defines in the instructions
const auto is{ cn.instructions->first };
const auto ie{ is + cn.instructions->count };
for ( auto ii = is ; ii < ie ; ii ++ ) {
auto const* const irec{ udPerInstr.get( ii ) };
if ( !irec ) {
continue;
}
const auto nrec{ irec->size( ) };
for ( auto j = 0u ; j < nrec ; j ++ ) {
auto const& rec{ (*irec)[ j ] };
if ( rec.isUse || data.varUDChains[ rec.entry ].var != var.var ) {
continue;
}
sInput.clear( );
sInput.add( rec.index );
}
}
}
auto& sOut{ defines[ node ] };
if ( sOut == sInput ) {
continue;
}
#if 0
data.logger( [&](){
T_StringBuilder sb;
sb << "Node " << node << ", setting output to {";
for ( auto i = 0u ; i < sInput.set.size( ) ; i ++ ) {
if ( i ) {
sb << " ,";
}
sb << ' ' << sInput.set[ i ];
}
sb << " }";
return sb;
} , LL2 );
#endif
sOut = sInput;
// Add the node's successors into the changed set
const auto nOut{ cn.outbound.size( ) };
for ( auto i = 0u ; i < nOut ; i ++ ) {
auto const& ob{ cn.outbound[ i ] };
// Make sure the outbound link type is right (FLOW
// always is, BYPASS works in functions, CALL/RET at
// the global level)
if ( ob.type != ob.FLOW && (
( fnIndex && ob.type != ob.BYPASS )
|| ( !fnIndex && ob.type == ob.BYPASS ) ) ) {
continue;
}
changed.add( ob.target );
}
}
// Now we need to identify the blocks which contain var uses
T_Set< uint32_t > blocks{ UseTag< ArrayBacked< 16 > >( ) }; // FIXME alloc
for ( auto i = 0u ; i < var.uses.size( ) ; i ++ ) {
const auto useInstr{ var.uses[ i ].node };
for ( auto j = nFirst ; j < nEnd ; j ++ ) {
auto const& block{ *data.ctrlFlowGraph[ j ] };
if ( !block.instructions ) {
continue;
}
const auto f{ block.instructions->first };
const auto e{ block.instructions->count + f - 1 };
if ( f <= useInstr && e >= useInstr ) {
blocks.add( j );
break;
}
}
}
// Now go through all the blocks instruction by instruction, updating
// the active definition set if a definition is found, and associating
// defines to uses.
for ( auto i = 0u ; i < blocks.size( ) ; i ++ ) {
const auto bid{ blocks[ i ] };
auto const& cb{ *data.ctrlFlowGraph[ bid ] };
T_BUDCDefSet_ defs{ defines[ bid ] };
assert( cb.instructions );
const auto is{ cb.instructions->first };
const auto ie{ is + cb.instructions->count };
for ( auto ii = is ; ii < ie ; ii ++ ) {
auto const* const irec{ udPerInstr.get( ii ) };
if ( !irec ) {
continue;
}
const auto nrec{ irec->size( ) };
// Handle uses first
for ( auto j = 0u ; j < nrec ; j ++ ) {
auto const& rec{ (*irec)[ j ] };
auto const& ud{ data.varUDChains[ rec.entry ] };
if ( !rec.isUse || ud.var != var.var ) {
continue;
}
for ( auto di = 0u ; di < defs.set.size( ) ; di ++ ) {
BUDCLink_( var , defs.set[ di ] ,
rec.index , data.logger );
}
if ( !defs.set.size( ) ) {
// FIXME: add warning
BUDCLink_( var , T_HashIndex::INVALID_INDEX ,
rec.index , data.logger );
}
}
// Update the set
for ( auto j = 0u ; j < nrec ; j ++ ) {
auto const& rec{ (*irec)[ j ] };
auto const& ud{ data.varUDChains[ rec.entry ] };
if ( rec.isUse || ud.var != var.var ) {
continue;
}
defs.clear( );
defs.add( rec.index );
break;
}
}
}
}
} // namespace <anon> } // namespace <anon>
@ -828,7 +1087,7 @@ void T_OptData::buildUseDefineChains(
for ( auto& sym : varUDChains.values( ) ) { for ( auto& sym : varUDChains.values( ) ) {
switch ( sym.var.type ) { switch ( sym.var.type ) {
case T_OptData::E_UDVarType::GLOBAL: case T_OptData::E_UDVarType::GLOBAL:
#warning TODO BUDCWalkGraph_( *this , sym , udPerInstr , {} );
break; break;
case T_OptData::E_UDVarType::ARGUMENT: { case T_OptData::E_UDVarType::ARGUMENT: {
@ -842,11 +1101,14 @@ void T_OptData::buildUseDefineChains(
break; break;
} }
case T_OptData::E_UDVarType::LOCAL: case T_OptData::E_UDVarType::LOCAL: {
#warning TODO assert( cfgFunctions.contains( sym.var.owner ) );
BUDCWalkGraph_( *this , sym , udPerInstr ,
cfgFunctions.indexOf( sym.var.owner ) );
break; break;
} }
} }
}
#if 0 #if 0
// Walk the graph from the entry point until all reachable nodes // Walk the graph from the entry point until all reachable nodes