Optimizer - WIP UD chain construction
This commit is contained in:
parent
be007f8f96
commit
61cd7719f1
2 changed files with 182 additions and 69 deletions
245
c-opopt.cc
245
c-opopt.cc
|
@ -27,6 +27,9 @@ uint32_t opopt::ComputeHash(
|
|||
^ ( ( oh << 29 ) | ( oh >> 3 ) );
|
||||
}
|
||||
|
||||
constexpr uint32_t T_OptData::CFG_ENTER;
|
||||
constexpr uint32_t T_OptData::CFG_MAINLOOP;
|
||||
constexpr uint32_t T_OptData::CFG_END;
|
||||
|
||||
/*= T_OptData - INPUT DECLARATIONS ===========================================*/
|
||||
|
||||
|
@ -123,7 +126,6 @@ namespace {
|
|||
// CFG type shortcuts
|
||||
using T_CFN_ = T_OptData::T_CtrlFlowNode;
|
||||
using P_CFN_ = T_OptData::P_CtrlFlowNode;
|
||||
using RP_CFN_ = T_OptData::RP_CtrlFlowNode;
|
||||
|
||||
// Helpers to create or re-use CFG nodes
|
||||
T_OptData::P_CtrlFlowNode BCFGNewNode_(
|
||||
|
@ -143,7 +145,9 @@ T_OptData::P_CtrlFlowNode BCFGNewNode_(
|
|||
|
||||
#define M_NEWNODE_() BCFGNewNode_( old )
|
||||
#define M_ADDNEW_() \
|
||||
ctrlFlowGraph[ ctrlFlowGraph.add( M_NEWNODE_( ) ) ].get( )
|
||||
ctrlFlowGraph.add( M_NEWNODE_( ) )
|
||||
#define M_NODE_(i) \
|
||||
ctrlFlowGraph[i]
|
||||
|
||||
} // namespace <anon>
|
||||
|
||||
|
@ -158,29 +162,29 @@ void T_OptData::buildControlFlowGraph(
|
|||
|
||||
// Create special nodes
|
||||
M_ADDNEW_( );
|
||||
const RP_CFN_ nMainLoop { M_ADDNEW_( ) };
|
||||
const RP_CFN_ nExit { M_ADDNEW_( ) };
|
||||
nMainLoop->outbound.add( nExit );
|
||||
nExit->inbound.add( nMainLoop );
|
||||
M_ADDNEW_( );
|
||||
M_ADDNEW_( );
|
||||
M_NODE_( CFG_MAINLOOP )->outbound.add( CFG_END );
|
||||
M_NODE_( CFG_END )->inbound.add( CFG_MAINLOOP );
|
||||
|
||||
// Data structure to handle conditionals
|
||||
struct T_StackEntry_ {
|
||||
RP_CFN_ condBlock;
|
||||
uint32_t condBlock;
|
||||
bool hasDefault{ false };
|
||||
T_AutoArray< RP_CFN_ , 8 > caseBlocks;
|
||||
T_AutoArray< uint32_t , 8 > caseBlocks;
|
||||
};
|
||||
|
||||
// Data structure for call sites
|
||||
struct T_CallSite_ {
|
||||
T_String name;
|
||||
RP_CFN_ callBlock;
|
||||
RP_CFN_ retBlock;
|
||||
uint32_t callBlock;
|
||||
uint32_t retBlock;
|
||||
};
|
||||
|
||||
// Generate control flow graph for each function
|
||||
T_AutoArray< T_StackEntry_ , 8 > stack;
|
||||
T_Array< T_CallSite_ > callSites;
|
||||
RP_CFN_ cNode{ nullptr };
|
||||
T_Optional< uint32_t > cNode{ };
|
||||
visitor.visit( program.root , [&]( A_Node& node , const bool exit ) {
|
||||
const auto nt{ node.type( ) };
|
||||
|
||||
|
@ -194,16 +198,16 @@ void T_OptData::buildControlFlowGraph(
|
|||
logger( [&](){
|
||||
T_StringBuilder sb;
|
||||
sb << "Function ended; last block had "
|
||||
<< ( cNode->instructions
|
||||
? cNode->instructions->count
|
||||
: 0 )
|
||||
<< ( M_NODE_( *cNode )->instructions
|
||||
? M_NODE_( *cNode )->instructions->count
|
||||
: 0 )
|
||||
<< " instructions";
|
||||
return sb;
|
||||
} , LL1 );
|
||||
auto* frec{ cfgFunctions.get( fn ) };
|
||||
assert( frec );
|
||||
frec->count = ctrlFlowGraph.size( ) - frec->first;
|
||||
cNode = nullptr;
|
||||
cNode.clear( );
|
||||
} else {
|
||||
logger( [&](){
|
||||
T_StringBuilder sb;
|
||||
|
@ -221,10 +225,11 @@ void T_OptData::buildControlFlowGraph(
|
|||
auto* const iptr{ dynamic_cast< A_InstructionNode* >( &node ) };
|
||||
if ( iptr && !exit ) {
|
||||
assert( cNode );
|
||||
if ( cNode->instructions ) {
|
||||
cNode->instructions->count ++;
|
||||
auto& n{ *M_NODE_( *cNode ) };
|
||||
if ( n.instructions ) {
|
||||
n.instructions->count ++;
|
||||
} else {
|
||||
cNode->instructions = T_BasicBlock{ indexOf( *iptr ) };
|
||||
n.instructions = T_BasicBlock{ indexOf( *iptr ) };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,15 +243,16 @@ void T_OptData::buildControlFlowGraph(
|
|||
// and the next block
|
||||
const auto ncb{ se.caseBlocks.size( ) };
|
||||
for ( auto i = 0u ; i < ncb ; i ++ ) {
|
||||
auto* cb{ se.caseBlocks[ i ] };
|
||||
cb->inbound.add( se.condBlock );
|
||||
se.condBlock->outbound.add( cb );
|
||||
cb->outbound.add( cNode );
|
||||
cNode->inbound.add( cb );
|
||||
auto& cbi{ se.caseBlocks[ i ] };
|
||||
auto& cb{ *M_NODE_( cbi ) };
|
||||
cb.inbound.add( se.condBlock );
|
||||
M_NODE_( se.condBlock )->outbound.add( cbi );
|
||||
cb.outbound.add( cNode );
|
||||
M_NODE_( *cNode )->inbound.add( cbi );
|
||||
}
|
||||
if ( !se.hasDefault ) {
|
||||
cNode->inbound.add( se.condBlock );
|
||||
se.condBlock->outbound.add( cNode );
|
||||
M_NODE_( *cNode )->inbound.add( se.condBlock );
|
||||
M_NODE_( se.condBlock )->outbound.add( *cNode );
|
||||
}
|
||||
|
||||
stack.removeLast( );
|
||||
|
@ -258,16 +264,16 @@ void T_OptData::buildControlFlowGraph(
|
|||
} , LL2 );
|
||||
} else {
|
||||
auto& se{ stack.addNew( ) };
|
||||
se.condBlock = cNode;
|
||||
cNode = nullptr;
|
||||
se.condBlock = *cNode;
|
||||
cNode.clear( );
|
||||
logger( [&](){
|
||||
T_StringBuilder sb;
|
||||
sb << "Entering conditional instruction, stack size "
|
||||
<< stack.size( )
|
||||
<< ", block had "
|
||||
<< ( se.condBlock->instructions
|
||||
? se.condBlock->instructions->count
|
||||
: 0 )
|
||||
<< ( M_NODE_( se.condBlock )->instructions
|
||||
? M_NODE_( se.condBlock )->instructions->count
|
||||
: 0 )
|
||||
<< " instructions";
|
||||
return sb;
|
||||
} , LL2 );
|
||||
|
@ -281,9 +287,9 @@ void T_OptData::buildControlFlowGraph(
|
|||
logger( [&](){
|
||||
T_StringBuilder sb;
|
||||
sb << "Call to " << ci.id( ) << ", block had "
|
||||
<< ( cNode->instructions
|
||||
? cNode->instructions->count
|
||||
: 0 )
|
||||
<< ( M_NODE_( *cNode )->instructions
|
||||
? M_NODE_( *cNode )->instructions->count
|
||||
: 0 )
|
||||
<< " instructions";
|
||||
return sb;
|
||||
} , LL2 );
|
||||
|
@ -301,13 +307,13 @@ void T_OptData::buildControlFlowGraph(
|
|||
logger( [&](){
|
||||
T_StringBuilder sb;
|
||||
sb << "Case block added ("
|
||||
<< ( cNode->instructions
|
||||
? cNode->instructions->count
|
||||
: 0 )
|
||||
<< ( M_NODE_( *cNode )->instructions
|
||||
? M_NODE_( *cNode )->instructions->count
|
||||
: 0 )
|
||||
<< " instructions)";
|
||||
return sb;
|
||||
} , LL2 );
|
||||
cNode = nullptr;
|
||||
cNode.clear( );
|
||||
} else {
|
||||
stack.last( ).hasDefault = stack.last( ).hasDefault
|
||||
|| ( nt == A_Node::TN_DEFAULT );
|
||||
|
@ -323,14 +329,14 @@ void T_OptData::buildControlFlowGraph(
|
|||
// Add fake call sites for *init* and *frame*
|
||||
{
|
||||
auto& cs{ callSites.addNew( ) };
|
||||
cs.callBlock = ctrlFlowGraph[ CFG_ENTER ].get( );
|
||||
cs.retBlock = ctrlFlowGraph[ CFG_MAINLOOP ].get( );
|
||||
cs.callBlock = CFG_ENTER;
|
||||
cs.retBlock = CFG_MAINLOOP;
|
||||
cs.name = "*init*";
|
||||
}
|
||||
{
|
||||
auto& cs{ callSites.addNew( ) };
|
||||
cs.callBlock = ctrlFlowGraph[ CFG_MAINLOOP ].get( );
|
||||
cs.retBlock = ctrlFlowGraph[ CFG_MAINLOOP ].get( );
|
||||
cs.callBlock = CFG_MAINLOOP;
|
||||
cs.retBlock = CFG_MAINLOOP;
|
||||
cs.name = "*frame*";
|
||||
}
|
||||
|
||||
|
@ -341,18 +347,20 @@ void T_OptData::buildControlFlowGraph(
|
|||
{
|
||||
auto& entry{ ctrlFlowGraph[ frec->first ] };
|
||||
entry->inbound.add( cs.callBlock );
|
||||
cs.callBlock->outbound.add( entry.get( ) );
|
||||
M_NODE_( cs.callBlock )->outbound.add( frec->first );
|
||||
}
|
||||
{
|
||||
auto& exit{ ctrlFlowGraph[ frec->first + frec->count - 1 ] };
|
||||
const auto n{ frec->first + frec->count - 1 };
|
||||
auto& exit{ ctrlFlowGraph[ n ] };
|
||||
exit->outbound.add( cs.retBlock );
|
||||
cs.retBlock->inbound.add( exit.get( ) );
|
||||
M_NODE_( cs.retBlock )->outbound.add( n );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef M_ADDNEW_
|
||||
#undef M_NEWNODE_
|
||||
#undef M_NODE_
|
||||
|
||||
|
||||
/*= T_OptData - USE/DEFINE CHAINS ============================================*/
|
||||
|
@ -552,24 +560,6 @@ void BUDCAddEntries_(
|
|||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
struct T_VarEvt_
|
||||
{
|
||||
enum E_VarEvt {
|
||||
DEF , USE , KILL
|
||||
};
|
||||
|
||||
uint32_t instrId;
|
||||
E_VarEvt evt;
|
||||
T_OptData::T_VarId var;
|
||||
|
||||
T_VarEvt_( uint32_t instrId , E_VarEvt evt ,
|
||||
T_OptData::T_VarId const& var )
|
||||
: instrId( instrId ) , evt( evt ) , var( var )
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
} // namespace <anon>
|
||||
|
||||
|
@ -599,9 +589,134 @@ void T_OptData::buildUseDefineChains(
|
|||
BUDCAddEntries_( udPerInstr , i , false , r.defines );
|
||||
}
|
||||
|
||||
// For each node of the CFG graph, we need to generate a sequence that
|
||||
// indicates what gets defined, used or killed.
|
||||
T_MultiArray< T_VarEvt_ > cfgVarEvents;
|
||||
// Walk the graph from the entry point until all reachable nodes
|
||||
// have been covered and keeping track of active definitions. When
|
||||
// the flow diverges, we need to store the state before the
|
||||
// divergence.
|
||||
const uint32_t nNodes{ ctrlFlowGraph.size( ) };
|
||||
uint32_t nProcessed{ 0 };
|
||||
uint32_t node{ CFG_ENTER };
|
||||
|
||||
bool processedNodes[ nNodes ];
|
||||
memset( processedNodes , 0 , sizeof( processedNodes ) );
|
||||
|
||||
using T_ActDefs_ = T_Array< uint32_t >;
|
||||
using P_ActDefs_ = T_OwnPtr< T_ActDefs_ >;
|
||||
P_ActDefs_ activeDefs{ NewOwned< T_ActDefs_ >( ) };
|
||||
activeDefs->resize( varUDChains.size( ) , T_HashIndex::INVALID_INDEX );
|
||||
|
||||
struct T_StackEntry_ {
|
||||
P_ActDefs_ def;
|
||||
uint32_t node;
|
||||
|
||||
T_StackEntry_( P_ActDefs_ const& src , const uint32_t n ) noexcept
|
||||
: def{ NewOwned< T_ActDefs_ >( *src ) } , node( n )
|
||||
{}
|
||||
};
|
||||
T_AutoArray< T_StackEntry_ , 32 > stack;
|
||||
|
||||
while ( nProcessed < nNodes ) {
|
||||
assert( !processedNodes[ node ] );
|
||||
auto const& cn{ *ctrlFlowGraph[ node ] };
|
||||
processedNodes[ node ] = true;
|
||||
logger( [=]() {
|
||||
T_StringBuilder sb;
|
||||
sb << "processing node " << node;
|
||||
return sb;
|
||||
} , LL2 );
|
||||
nProcessed ++;
|
||||
|
||||
if ( cn.instructions ) {
|
||||
// Check for uses and 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( ) };
|
||||
|
||||
// Handle uses first
|
||||
for ( auto j = 0u ; j < nrec ; j ++ ) {
|
||||
auto const& rec{ (*irec)[ j ] };
|
||||
if ( !rec.isUse ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& resource{ varUDChains[ rec.entry ] };
|
||||
const auto defId{ (*activeDefs)[ rec.entry ] };
|
||||
// FIXME: must be defined
|
||||
resource.defines[ defId ].refs.add( rec.index );
|
||||
resource.uses[ rec.index ].refs.add( defId );
|
||||
logger( [&](){
|
||||
T_StringBuilder sb;
|
||||
sb << "USE " << resource.var.name
|
||||
<< " @ instr #" << ii
|
||||
<< ", def " << defId;
|
||||
return sb;
|
||||
} , LL2 );
|
||||
}
|
||||
|
||||
// Handle defines
|
||||
for ( auto j = 0u ; j < nrec ; j ++ ) {
|
||||
auto const& rec{ (*irec)[ j ] };
|
||||
if ( rec.isUse ) {
|
||||
continue;
|
||||
}
|
||||
(*activeDefs)[ rec.entry ] = rec.index;
|
||||
logger( [&](){
|
||||
T_StringBuilder sb;
|
||||
sb << "DEF " << rec.index
|
||||
<< varUDChains[ rec.entry ].var.name
|
||||
<< " @ instr #" << ii;
|
||||
return sb;
|
||||
} , LL2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( nProcessed == nNodes ) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for possible next nodes
|
||||
// -> no output nodes left -> pop stack and keep trying,
|
||||
// unless we've already processed all nodes
|
||||
// -> if there's only one, use it and don't push to stack
|
||||
// -> otherwise push to stack, use first available node
|
||||
do {
|
||||
auto const& rcn{ *ctrlFlowGraph[ node ] };
|
||||
const uint32_t nSuccs{ [&](){
|
||||
const auto no{ rcn.outbound.size( ) };
|
||||
uint32_t c{ 0 };
|
||||
for ( auto i = 0u ; i < no ; i ++ ) {
|
||||
if ( !processedNodes[ rcn.outbound[ i ] ] ) {
|
||||
c ++;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}() };
|
||||
logger( [=]() {
|
||||
T_StringBuilder sb;
|
||||
sb << "node " << node << ": " << nSuccs
|
||||
<< " successor(s) left";
|
||||
return sb;
|
||||
} , LL2 );
|
||||
|
||||
if ( nSuccs == 0 ) {
|
||||
assert( !stack.empty( ) );
|
||||
node = stack.last( ).node;
|
||||
activeDefs = std::move( stack.last( ).def );
|
||||
stack.removeLast( );
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO cases in which there is one or more successors
|
||||
} while ( 0 ); // XXX
|
||||
|
||||
// 30 if next block is an end of function, kill locals
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -67,13 +67,11 @@ struct T_OptData
|
|||
};
|
||||
|
||||
// Control flow graph node
|
||||
struct T_CtrlFlowNode;
|
||||
using RP_CtrlFlowNode = T_CtrlFlowNode*;
|
||||
struct T_CtrlFlowNode
|
||||
{
|
||||
T_Optional< T_BasicBlock > instructions;
|
||||
T_AutoArray< RP_CtrlFlowNode , 16 > inbound;
|
||||
T_AutoArray< RP_CtrlFlowNode , 16 > outbound;
|
||||
T_AutoArray< uint32_t , 16 > inbound;
|
||||
T_AutoArray< uint32_t , 16 > outbound;
|
||||
};
|
||||
using P_CtrlFlowNode = T_OwnPtr< T_CtrlFlowNode >;
|
||||
|
||||
|
|
Loading…
Reference in a new issue