Optimizer - Edge types in CFG

Control flow graph edges have been assigned a type, which may be either
FLOW (for normal edges), CALL (for edges that enter a function) or RET
(for edges that exit a function). In addition, call sites have an
additional FLOW edge that bypasses the function call.
This commit is contained in:
Emmanuel BENOîT 2017-12-10 11:12:45 +01:00
parent ddad981055
commit cb42137592
2 changed files with 53 additions and 15 deletions

View file

@ -27,6 +27,19 @@ uint32_t opopt::ComputeHash(
^ ( ( oh << 29 ) | ( oh >> 3 ) );
}
T_StringBuilder& opopt::operator<<(
T_StringBuilder& obj ,
T_OptData::T_CtrlFlowEdge const& value ) noexcept
{
obj << value.target;
if ( value.type == T_OptData::T_CtrlFlowEdge::CALL ) {
obj << "{c}";
} else if ( value.type == T_OptData::T_CtrlFlowEdge::RET ) {
obj << "{r}";
}
return obj;
}
constexpr uint32_t T_OptData::CFG_ENTER;
constexpr uint32_t T_OptData::CFG_MAINLOOP;
constexpr uint32_t T_OptData::CFG_END;
@ -386,21 +399,30 @@ inline void BCFGHandleCalls_(
}
// Handle calls
constexpr auto tCall{ T_OptData::T_CtrlFlowEdge::CALL };
constexpr auto tRet{ T_OptData::T_CtrlFlowEdge::RET };
for ( auto const& cs : data.callSites ) {
auto const* frec{ data.cfgFunctions.get( cs.name ) };
assert( frec );
{
auto& entry{ data.ctrlFlowGraph[ frec->first ] };
entry->inbound.add( cs.callBlock );
data.ctrlFlowGraph[ cs.callBlock ]->outbound.add(
frec->first );
}
{
const auto n{ frec->first + frec->count - 1 };
auto& exit{ data.ctrlFlowGraph[ n ] };
exit->outbound.add( cs.retBlock );
data.ctrlFlowGraph[ cs.retBlock ]->inbound.add( n );
}
const auto nExit{ frec->first + frec->count - 1 };
auto& bCall{ *data.ctrlFlowGraph[ cs.callBlock ] };
auto& bRet{ *data.ctrlFlowGraph[ cs.retBlock ] };
auto& bEntry{ *data.ctrlFlowGraph[ frec->first ] };
auto& bExit{ *data.ctrlFlowGraph[ nExit ] };
// Call
bEntry.inbound.addNew( cs.callBlock , tCall );
bCall.outbound.addNew( frec->first , tCall );
// Return
bExit.outbound.addNew( cs.retBlock , tRet );
bRet.inbound.addNew( nExit , tRet );
// Normal flow, skipping the call
bCall.outbound.addNew( cs.retBlock );
bRet.inbound.addNew( cs.callBlock );
}
}

View file

@ -66,12 +66,27 @@ struct T_OptData
{ }
};
// Control flow graph node
// Control flow graph edges and nodes
struct T_CtrlFlowEdge
{
enum E_Type {
FLOW , CALL , RET
};
uint32_t target;
E_Type type;
T_CtrlFlowEdge(
const uint32_t target ,
const E_Type type = FLOW ) noexcept
: target{ target } , type{ type }
{}
};
struct T_CtrlFlowNode
{
T_Optional< T_BasicBlock > instructions;
T_AutoArray< uint32_t , 16 > inbound;
T_AutoArray< uint32_t , 16 > outbound;
T_AutoArray< T_CtrlFlowEdge , 16 > inbound;
T_AutoArray< T_CtrlFlowEdge , 16 > outbound;
};
using P_CtrlFlowNode = T_OwnPtr< T_CtrlFlowNode >;
@ -171,6 +186,7 @@ struct T_OptData
};
uint32_t ComputeHash( T_OptData::T_VarId const& id ) noexcept;
M_LSHIFT_OP( T_StringBuilder , T_OptData::T_CtrlFlowEdge const& ) noexcept;
/*= INDIVIDUAL OPTIMISATIONS =================================================*/