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 ) );
|
^ ( ( 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 ===========================================*/
|
/*= T_OptData - INPUT DECLARATIONS ===========================================*/
|
||||||
|
|
||||||
|
@ -123,7 +126,6 @@ namespace {
|
||||||
// CFG type shortcuts
|
// CFG type shortcuts
|
||||||
using T_CFN_ = T_OptData::T_CtrlFlowNode;
|
using T_CFN_ = T_OptData::T_CtrlFlowNode;
|
||||||
using P_CFN_ = T_OptData::P_CtrlFlowNode;
|
using P_CFN_ = T_OptData::P_CtrlFlowNode;
|
||||||
using RP_CFN_ = T_OptData::RP_CtrlFlowNode;
|
|
||||||
|
|
||||||
// Helpers to create or re-use CFG nodes
|
// Helpers to create or re-use CFG nodes
|
||||||
T_OptData::P_CtrlFlowNode BCFGNewNode_(
|
T_OptData::P_CtrlFlowNode BCFGNewNode_(
|
||||||
|
@ -143,7 +145,9 @@ T_OptData::P_CtrlFlowNode BCFGNewNode_(
|
||||||
|
|
||||||
#define M_NEWNODE_() BCFGNewNode_( old )
|
#define M_NEWNODE_() BCFGNewNode_( old )
|
||||||
#define M_ADDNEW_() \
|
#define M_ADDNEW_() \
|
||||||
ctrlFlowGraph[ ctrlFlowGraph.add( M_NEWNODE_( ) ) ].get( )
|
ctrlFlowGraph.add( M_NEWNODE_( ) )
|
||||||
|
#define M_NODE_(i) \
|
||||||
|
ctrlFlowGraph[i]
|
||||||
|
|
||||||
} // namespace <anon>
|
} // namespace <anon>
|
||||||
|
|
||||||
|
@ -158,29 +162,29 @@ void T_OptData::buildControlFlowGraph(
|
||||||
|
|
||||||
// Create special nodes
|
// Create special nodes
|
||||||
M_ADDNEW_( );
|
M_ADDNEW_( );
|
||||||
const RP_CFN_ nMainLoop { M_ADDNEW_( ) };
|
M_ADDNEW_( );
|
||||||
const RP_CFN_ nExit { M_ADDNEW_( ) };
|
M_ADDNEW_( );
|
||||||
nMainLoop->outbound.add( nExit );
|
M_NODE_( CFG_MAINLOOP )->outbound.add( CFG_END );
|
||||||
nExit->inbound.add( nMainLoop );
|
M_NODE_( CFG_END )->inbound.add( CFG_MAINLOOP );
|
||||||
|
|
||||||
// Data structure to handle conditionals
|
// Data structure to handle conditionals
|
||||||
struct T_StackEntry_ {
|
struct T_StackEntry_ {
|
||||||
RP_CFN_ condBlock;
|
uint32_t condBlock;
|
||||||
bool hasDefault{ false };
|
bool hasDefault{ false };
|
||||||
T_AutoArray< RP_CFN_ , 8 > caseBlocks;
|
T_AutoArray< uint32_t , 8 > caseBlocks;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Data structure for call sites
|
// Data structure for call sites
|
||||||
struct T_CallSite_ {
|
struct T_CallSite_ {
|
||||||
T_String name;
|
T_String name;
|
||||||
RP_CFN_ callBlock;
|
uint32_t callBlock;
|
||||||
RP_CFN_ retBlock;
|
uint32_t retBlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate control flow graph for each function
|
// Generate control flow graph for each function
|
||||||
T_AutoArray< T_StackEntry_ , 8 > stack;
|
T_AutoArray< T_StackEntry_ , 8 > stack;
|
||||||
T_Array< T_CallSite_ > callSites;
|
T_Array< T_CallSite_ > callSites;
|
||||||
RP_CFN_ cNode{ nullptr };
|
T_Optional< uint32_t > cNode{ };
|
||||||
visitor.visit( program.root , [&]( A_Node& node , const bool exit ) {
|
visitor.visit( program.root , [&]( A_Node& node , const bool exit ) {
|
||||||
const auto nt{ node.type( ) };
|
const auto nt{ node.type( ) };
|
||||||
|
|
||||||
|
@ -194,16 +198,16 @@ void T_OptData::buildControlFlowGraph(
|
||||||
logger( [&](){
|
logger( [&](){
|
||||||
T_StringBuilder sb;
|
T_StringBuilder sb;
|
||||||
sb << "Function ended; last block had "
|
sb << "Function ended; last block had "
|
||||||
<< ( cNode->instructions
|
<< ( M_NODE_( *cNode )->instructions
|
||||||
? cNode->instructions->count
|
? M_NODE_( *cNode )->instructions->count
|
||||||
: 0 )
|
: 0 )
|
||||||
<< " instructions";
|
<< " instructions";
|
||||||
return sb;
|
return sb;
|
||||||
} , LL1 );
|
} , LL1 );
|
||||||
auto* frec{ cfgFunctions.get( fn ) };
|
auto* frec{ cfgFunctions.get( fn ) };
|
||||||
assert( frec );
|
assert( frec );
|
||||||
frec->count = ctrlFlowGraph.size( ) - frec->first;
|
frec->count = ctrlFlowGraph.size( ) - frec->first;
|
||||||
cNode = nullptr;
|
cNode.clear( );
|
||||||
} else {
|
} else {
|
||||||
logger( [&](){
|
logger( [&](){
|
||||||
T_StringBuilder sb;
|
T_StringBuilder sb;
|
||||||
|
@ -221,10 +225,11 @@ void T_OptData::buildControlFlowGraph(
|
||||||
auto* const iptr{ dynamic_cast< A_InstructionNode* >( &node ) };
|
auto* const iptr{ dynamic_cast< A_InstructionNode* >( &node ) };
|
||||||
if ( iptr && !exit ) {
|
if ( iptr && !exit ) {
|
||||||
assert( cNode );
|
assert( cNode );
|
||||||
if ( cNode->instructions ) {
|
auto& n{ *M_NODE_( *cNode ) };
|
||||||
cNode->instructions->count ++;
|
if ( n.instructions ) {
|
||||||
|
n.instructions->count ++;
|
||||||
} else {
|
} 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
|
// and the next block
|
||||||
const auto ncb{ se.caseBlocks.size( ) };
|
const auto ncb{ se.caseBlocks.size( ) };
|
||||||
for ( auto i = 0u ; i < ncb ; i ++ ) {
|
for ( auto i = 0u ; i < ncb ; i ++ ) {
|
||||||
auto* cb{ se.caseBlocks[ i ] };
|
auto& cbi{ se.caseBlocks[ i ] };
|
||||||
cb->inbound.add( se.condBlock );
|
auto& cb{ *M_NODE_( cbi ) };
|
||||||
se.condBlock->outbound.add( cb );
|
cb.inbound.add( se.condBlock );
|
||||||
cb->outbound.add( cNode );
|
M_NODE_( se.condBlock )->outbound.add( cbi );
|
||||||
cNode->inbound.add( cb );
|
cb.outbound.add( cNode );
|
||||||
|
M_NODE_( *cNode )->inbound.add( cbi );
|
||||||
}
|
}
|
||||||
if ( !se.hasDefault ) {
|
if ( !se.hasDefault ) {
|
||||||
cNode->inbound.add( se.condBlock );
|
M_NODE_( *cNode )->inbound.add( se.condBlock );
|
||||||
se.condBlock->outbound.add( cNode );
|
M_NODE_( se.condBlock )->outbound.add( *cNode );
|
||||||
}
|
}
|
||||||
|
|
||||||
stack.removeLast( );
|
stack.removeLast( );
|
||||||
|
@ -258,16 +264,16 @@ void T_OptData::buildControlFlowGraph(
|
||||||
} , LL2 );
|
} , LL2 );
|
||||||
} else {
|
} else {
|
||||||
auto& se{ stack.addNew( ) };
|
auto& se{ stack.addNew( ) };
|
||||||
se.condBlock = cNode;
|
se.condBlock = *cNode;
|
||||||
cNode = nullptr;
|
cNode.clear( );
|
||||||
logger( [&](){
|
logger( [&](){
|
||||||
T_StringBuilder sb;
|
T_StringBuilder sb;
|
||||||
sb << "Entering conditional instruction, stack size "
|
sb << "Entering conditional instruction, stack size "
|
||||||
<< stack.size( )
|
<< stack.size( )
|
||||||
<< ", block had "
|
<< ", block had "
|
||||||
<< ( se.condBlock->instructions
|
<< ( M_NODE_( se.condBlock )->instructions
|
||||||
? se.condBlock->instructions->count
|
? M_NODE_( se.condBlock )->instructions->count
|
||||||
: 0 )
|
: 0 )
|
||||||
<< " instructions";
|
<< " instructions";
|
||||||
return sb;
|
return sb;
|
||||||
} , LL2 );
|
} , LL2 );
|
||||||
|
@ -281,9 +287,9 @@ void T_OptData::buildControlFlowGraph(
|
||||||
logger( [&](){
|
logger( [&](){
|
||||||
T_StringBuilder sb;
|
T_StringBuilder sb;
|
||||||
sb << "Call to " << ci.id( ) << ", block had "
|
sb << "Call to " << ci.id( ) << ", block had "
|
||||||
<< ( cNode->instructions
|
<< ( M_NODE_( *cNode )->instructions
|
||||||
? cNode->instructions->count
|
? M_NODE_( *cNode )->instructions->count
|
||||||
: 0 )
|
: 0 )
|
||||||
<< " instructions";
|
<< " instructions";
|
||||||
return sb;
|
return sb;
|
||||||
} , LL2 );
|
} , LL2 );
|
||||||
|
@ -301,13 +307,13 @@ void T_OptData::buildControlFlowGraph(
|
||||||
logger( [&](){
|
logger( [&](){
|
||||||
T_StringBuilder sb;
|
T_StringBuilder sb;
|
||||||
sb << "Case block added ("
|
sb << "Case block added ("
|
||||||
<< ( cNode->instructions
|
<< ( M_NODE_( *cNode )->instructions
|
||||||
? cNode->instructions->count
|
? M_NODE_( *cNode )->instructions->count
|
||||||
: 0 )
|
: 0 )
|
||||||
<< " instructions)";
|
<< " instructions)";
|
||||||
return sb;
|
return sb;
|
||||||
} , LL2 );
|
} , LL2 );
|
||||||
cNode = nullptr;
|
cNode.clear( );
|
||||||
} else {
|
} else {
|
||||||
stack.last( ).hasDefault = stack.last( ).hasDefault
|
stack.last( ).hasDefault = stack.last( ).hasDefault
|
||||||
|| ( nt == A_Node::TN_DEFAULT );
|
|| ( nt == A_Node::TN_DEFAULT );
|
||||||
|
@ -323,14 +329,14 @@ void T_OptData::buildControlFlowGraph(
|
||||||
// Add fake call sites for *init* and *frame*
|
// Add fake call sites for *init* and *frame*
|
||||||
{
|
{
|
||||||
auto& cs{ callSites.addNew( ) };
|
auto& cs{ callSites.addNew( ) };
|
||||||
cs.callBlock = ctrlFlowGraph[ CFG_ENTER ].get( );
|
cs.callBlock = CFG_ENTER;
|
||||||
cs.retBlock = ctrlFlowGraph[ CFG_MAINLOOP ].get( );
|
cs.retBlock = CFG_MAINLOOP;
|
||||||
cs.name = "*init*";
|
cs.name = "*init*";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto& cs{ callSites.addNew( ) };
|
auto& cs{ callSites.addNew( ) };
|
||||||
cs.callBlock = ctrlFlowGraph[ CFG_MAINLOOP ].get( );
|
cs.callBlock = CFG_MAINLOOP;
|
||||||
cs.retBlock = ctrlFlowGraph[ CFG_MAINLOOP ].get( );
|
cs.retBlock = CFG_MAINLOOP;
|
||||||
cs.name = "*frame*";
|
cs.name = "*frame*";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,18 +347,20 @@ void T_OptData::buildControlFlowGraph(
|
||||||
{
|
{
|
||||||
auto& entry{ ctrlFlowGraph[ frec->first ] };
|
auto& entry{ ctrlFlowGraph[ frec->first ] };
|
||||||
entry->inbound.add( cs.callBlock );
|
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 );
|
exit->outbound.add( cs.retBlock );
|
||||||
cs.retBlock->inbound.add( exit.get( ) );
|
M_NODE_( cs.retBlock )->outbound.add( n );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef M_ADDNEW_
|
#undef M_ADDNEW_
|
||||||
#undef M_NEWNODE_
|
#undef M_NEWNODE_
|
||||||
|
#undef M_NODE_
|
||||||
|
|
||||||
|
|
||||||
/*= T_OptData - USE/DEFINE CHAINS ============================================*/
|
/*= 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>
|
} // namespace <anon>
|
||||||
|
|
||||||
|
@ -599,9 +589,134 @@ void T_OptData::buildUseDefineChains(
|
||||||
BUDCAddEntries_( udPerInstr , i , false , r.defines );
|
BUDCAddEntries_( udPerInstr , i , false , r.defines );
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each node of the CFG graph, we need to generate a sequence that
|
// Walk the graph from the entry point until all reachable nodes
|
||||||
// indicates what gets defined, used or killed.
|
// have been covered and keeping track of active definitions. When
|
||||||
T_MultiArray< T_VarEvt_ > cfgVarEvents;
|
// 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
|
// Control flow graph node
|
||||||
struct T_CtrlFlowNode;
|
|
||||||
using RP_CtrlFlowNode = T_CtrlFlowNode*;
|
|
||||||
struct T_CtrlFlowNode
|
struct T_CtrlFlowNode
|
||||||
{
|
{
|
||||||
T_Optional< T_BasicBlock > instructions;
|
T_Optional< T_BasicBlock > instructions;
|
||||||
T_AutoArray< RP_CtrlFlowNode , 16 > inbound;
|
T_AutoArray< uint32_t , 16 > inbound;
|
||||||
T_AutoArray< RP_CtrlFlowNode , 16 > outbound;
|
T_AutoArray< uint32_t , 16 > outbound;
|
||||||
};
|
};
|
||||||
using P_CtrlFlowNode = T_OwnPtr< T_CtrlFlowNode >;
|
using P_CtrlFlowNode = T_OwnPtr< T_CtrlFlowNode >;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue