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 + -
显示快捷键?