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 );
|
} , 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
|
||||||
|
|
Loading…
Reference in a new issue