Optimizer - UD chains - WORKING (fo'real, man)
Horrible, spaghettish, slow, memory hungry but WORKING implementation of use/define chains!!!!
This commit is contained in:
parent
cc519be077
commit
7e5d782d2f
1 changed files with 265 additions and 3 deletions
268
c-opopt.cc
268
c-opopt.cc
|
@ -761,6 +761,265 @@ void BUDCLink_(
|
|||
} , 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>
|
||||
|
||||
|
@ -828,7 +1087,7 @@ void T_OptData::buildUseDefineChains(
|
|||
for ( auto& sym : varUDChains.values( ) ) {
|
||||
switch ( sym.var.type ) {
|
||||
case T_OptData::E_UDVarType::GLOBAL:
|
||||
#warning TODO
|
||||
BUDCWalkGraph_( *this , sym , udPerInstr , {} );
|
||||
break;
|
||||
|
||||
case T_OptData::E_UDVarType::ARGUMENT: {
|
||||
|
@ -842,9 +1101,12 @@ void T_OptData::buildUseDefineChains(
|
|||
break;
|
||||
}
|
||||
|
||||
case T_OptData::E_UDVarType::LOCAL:
|
||||
#warning TODO
|
||||
case T_OptData::E_UDVarType::LOCAL: {
|
||||
assert( cfgFunctions.contains( sym.var.owner ) );
|
||||
BUDCWalkGraph_( *this , sym , udPerInstr ,
|
||||
cfgFunctions.indexOf( sym.var.owner ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue