cgbkcgrf.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,508 行 · 第 1/4 页
C
1,508 行
CALLGRAPH *ctl, // - control information
CALLNODE *node ) // - function in graph
{
INLINEE *inl; // - pushed inline entry
inl = VstkPush( &ctl->calls );
inl->callee = node;
inl->expanded = FALSE;
}
static void scanVftDefn( // SCAN VFT DEFINITION
CALLNODE *cnode, // - node in call graph for calling function
SYMBOL vft, // - symbol for VFT
CGFILE **pvfcg ) // - cached CGFILE pointer
{
VFT_DEFN* srch; // - current VFT in search
VFT_DEFN* pvft; // - VFT entry for symbol
CGINTER* ins; // - current instruction
SYMBOL sym; // - vfn symbol
if( cnode->calls_done ) {
return;
}
call_graph->scanning = NULL;
cnode->calls_done = TRUE;
ExtraRptIncrementCtr( ctr_vfts_genned );
_DUMP_CGRF( "scan VFT body: %s\n", vft );
pvft = NULL;
vft->flag |= SF_REFERENCED;
RingIterBeg( vft_defs, srch ) {
if( srch->vft == vft ) {
pvft = srch;
break;
}
} RingIterEnd( srch );
DbgVerify( pvft != NULL, "ScanVftDefn -- can't find VFT" );
if( pvft->cgfile != *pvfcg ) {
if( *pvfcg != NULL ) {
CgioCloseInputFile( *pvfcg );
}
*pvfcg = pvft->cgfile;
CgioOpenInput( *pvfcg );
}
ins = CgioSeek( *pvfcg, &(pvft->location) );
for(;;) {
ins = CgioReadICMask( *pvfcg, ICOPM_VFT_SCAN );
// The following comment is a trigger for the ICMASK program to start
// scanning for case IC_* patterns.
// ICMASK BEGIN VFT_SCAN (do not remove)
switch( ins->opcode ) {
case IC_INIT_DONE:
break;
case IC_DATA_PTR_SYM:
sym = ins->value.pvalue;
sym->flag |= SF_IN_VFT;
addAddrOf( cnode, sym );
continue;
default:
DbgNever();
}
// ICMASK END (do not remove)
break;
}
}
// initial pass building call graph
// - add only nodes for inlines, statics
// - otherwise, add node and scan body
// - inlines which cannot be inlined are made static
//
static void scanFunction( // SCAN FUNCTION FOR CALLS
CGFILE *file_ctl ) // - current file
{
SYMBOL func; // - function symbol
CALLNODE *cnode; // - node in call graph for calling function
func = file_ctl->symbol;
cnode = addNode( func );
if( SymIsThunk( func ) ) {
SegmentMarkUsed( func->segid );
}
switch( cgbackFuncType( func ) ) {
case TCF_INLINE :
if( ! cnode->inlineable ) {
cnode->depth = max_inline_depth + 1;
_DUMP_CGRF( "static'ed inline function: %s\n", func );
}
if( SymIsMustGen( func ) ) {
scanFunctionBody( cnode, file_ctl );
forceGeneration( cnode );
}
break;
case TCF_STATIC :
#if 1
if( ! SymIsRegularStaticFunc( func ) || SymIsMustGen( func ) ) {
scanFunctionBody( cnode, file_ctl );
forceGeneration( cnode );
}
#else
if( SymIsMustGen( func ) ) {
scanFunctionBody( cnode, file_ctl );
forceGeneration( cnode );
} else if( ! SymIsRegularStaticFunc( func ) ) {
scanFunctionBody( cnode, file_ctl );
if( ! cnode->inlineable ) {
forceGeneration( cnode );
}
}
#endif
break;
default :
/* func may be NULL in this path */
scanFunctionBody( cnode, file_ctl );
if( func != NULL && SymIsMustGen( func ) ) {
forceGeneration( cnode );
}
}
}
static void checkForExpandOnceInlines( // scan for "at most 1" inline requests
CALLGRAPH *ctl, // - control info
INLINEE *last ) // - last call to check
{
INLINEE *stk; // - stacked inlinee
CGFILE *cgfile; // - function codegen file
SYMBOL func; // - called function
stk = VstkTop( &ctl->calls );
for(;;) {
if( stk == NULL ) break;
if( stk->expanded ) {
func = stk->callee->base.object;
if( func != NULL ) {
cgfile = nodeCgFile( stk->callee );
if( cgfile != NULL ) {
// found a max 1 inline function
if( cgfile->once_inl ) {
// make it out of line
cgfile->oe_inl = FALSE;
cgfile->once_inl = FALSE;
}
}
}
}
if( stk == last ) break;
stk = VstkNext( &ctl->calls, stk );
}
}
static boolean recursiveExpand( // DETERMINE IF RECURSIVE EXPANSION
CALLGRAPH *ctl, // - control information
CALLNODE *target ) // - node for caller
{
INLINEE *stk; // - stacked inlinee
stk = VstkTop( &ctl->calls );
while( stk != NULL ) {
if( stk->expanded && ( stk->callee == target ) ) {
if( callGraphFlags.only_once_found ) {
// a recursion will cause multiple expansions of an inline
// in this call path (at least one inline + one out of line)
checkForExpandOnceInlines( ctl, stk );
}
return( TRUE );
}
stk = VstkNext( &ctl->calls, stk );
}
return( FALSE );
}
static void markAsGen( // MARK CODE FILE TO BE GENERATED
CALLNODE *node ) // - function in graph
{
SYMBOL func; // - the function
CGFILE *cgfile; // - code gen file
if( ! node->is_vft ) {
cgfile = nodeCgFile( node );
if( cgfile != NULL && ! cgfile->refed ) {
func = callNodeCaller( node );
ExtraRptIncrementCtr( ctr_gened );
cgfile->refed = TRUE;
if( NULL != func ) {
SegmentMarkUsed( func->segid );
}
#ifndef NDEBUG
if( PragDbgToggle.dump_emit_ic ) {
printf( "Selected code file: %s\n"
, DbgSymNameFull( func ) );
}
#endif
}
}
}
static void forceGeneration( // FORCE CODE FILE TO BE GENERATED
CALLNODE *node ) // - function in graph
{
markAsGen( node );
// make sure we won't be pruned!
node->addrs++;
}
static boolean procEdge( // PROCESS EDGE IN CALL GRAPH
CALLGRAPH *ctl, // - control information
CALLEDGE *edge ) // - call to inline/static
{
CALLNODE *target; // - node for caller
ExtraRptIncrementCtr( ctr_nodes_visited );
target = (CALLNODE*)edge->base.target;
if( target->inlineable || target->inlineable_oe ) {
if( recursiveExpand( ctl, target ) ) {
target->depth = max_inline_depth + 1;
markAsGen( target );
if( ! target->flowed_recurse ) {
target->flowed_recurse = TRUE;
pushCaller( ctl, target );
}
} else {
CALLNODE* curr_node;
curr_node = ctl->curr_node;
if( ! curr_node->is_vft ) {
CGFILE* cgfile;
cgfile = nodeCgFile( curr_node );
cgfile->calls_inline = TRUE;
}
pushCaller( ctl, target );
}
} else {
if( target->inline_fun ) {
target->depth = max_inline_depth + 1;
markAsGen( target );
}
target->depth = 1;
}
return FALSE;
}
static void genFunction( // INDICATE FUNCTION NEEDS TO BE GEN'ED
CALLNODE *node ) // - function in graph
{
SYMBOL func; // - function symbol
func = node->base.object;
switch( cgbackFuncType( func ) ) {
case TCF_STATIC :
{ CGFILE* cgfile = nodeCgFile( node );
if( ! cgfile->once_inl
&& ! cgfile->oe_inl ) {
markAsGen( node );
break;
}
} // drops thru
case TCF_INLINE :
if( node->depth > max_inline_depth ) {
markAsGen( node );
}
break;
case TCF_VFT :
break;
default :
markAsGen( node );
break;
}
}
static boolean procInlineFunction( // PROCESS INLINE FUNCTIONS IN CALL GRAPH
CALLGRAPH *ctl, // - control information
CALLNODE *node ) // - function in graph
{
INLINEE *inl; // - stacked inline
unsigned depth; // - current depth
SYMBOL func; // - starting function
ExtraRptIncrementCtr( ctr_nodes_visited );
func = node->base.object;
if( func != NULL
&& node->addrs == 0
&& node->inline_fun
&& node->inlineable ) {
return( FALSE );
}
ctl->depth = 1;
pushCaller( ctl, node );
depth = 0;
for( ; ; ) {
inl = VstkTop( &ctl->calls );
if( inl == NULL ) break;
if( inl->expanded ) {
inl = VstkPop( &ctl->calls );
-- depth;
if( depth == 0 ) {
depth = max_inline_depth + 1;
}
} else {
ExtraRptIncrementCtr( ctr_nodes_visited );
inl->expanded = TRUE;
node = inl->callee;
if( depth > node->depth ) {
node->depth = depth;
}
if( depth > max_inline_depth ) {
genFunction( node );
depth = 0;
}
++ depth;
ctl->depth = depth;
CgrfWalkCalls( ctl, node, &procEdge );
}
}
return FALSE;
}
// Static functions include all defined functions when /oe is specified
//
static boolean procStaticFunction( // PROCESS STATIC FUNCTIONS IN CALL GRAPH
CALLGRAPH *ctl, // - control information
CALLNODE *node ) // - function in graph
{
SYMBOL func; // - function
CGFILE *cgfile; // - cg file for function
struct {
unsigned oe_small : 1; // - function is small enough to be -oe inlined
unsigned oe_static : 1; // - static function is called once
} flags;
ctl = ctl;
ExtraRptIncrementCtr( ctr_nodes_visited );
// if( node->inlineable && node->addrs == 0 ) {
if( node->inlineable ) {
func = node->base.object;
if( TCF_STATIC == cgbackFuncType( func ) ) {
flags.oe_small = FALSE;
flags.oe_static = FALSE;
if( node->opcodes <= oe_size ) {
flags.oe_small = TRUE;
#if 0
} else if( node->refs == 1 && SymIsRegularStaticFunc( func ) ) {
flags.oe_static = TRUE;
#else
} else if( node->refs == 1 ) {
flags.oe_static = TRUE;
#endif
}
if( flags.oe_small || flags.oe_static ) {
cgfile = nodeCgFile( node );
if( cgfile != NULL ) {
cgfile->oe_inl = TRUE;
if( flags.oe_static ) {
// we are inlining a static function that is called once
// (mark it so that it only gets inlined once!)
cgfile->once_inl = TRUE;
callGraphFlags.only_once_found = TRUE;
_DUMP_CGRF( "inlined once-called static function: %s\n", func );
} else {
_DUMP_CGRF( "inlined a global function: %s\n", func );
}
}
}
}
}
return FALSE;
}
static void removeCodeFile( // REMOVE CODE FILE FOR FUNCTION
CALLNODE* node ) // - node of function to be removed
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?