cgbkcgrf.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,508 行 · 第 1/4 页

C
1,508
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include "plusplus.h"

#include <float.h>

#include "cgfront.h"
#include "cgback.h"
#include "memmgr.h"
#include "errdefns.h"
#include "codegen.h"
#include "cgbackut.h"
#include "cppdwarf.h"
#include "cgaux.h"
#include "cginfo.h"
#include "ring.h"
#include "stringl.h"
#include "rtfuncod.h"
#include "carve.h"
#include "label.h"
#include "vstk.h"
#include "context.h"
#include "name.h"
#include "ctexcept.h"
#include "symdbg.h"
#include "callgrph.h"
#include "cdopt.h"
#include "stats.h"
#include "reposit.h"
#include "scoperes.h"
#include "icopmask.h"
#include "pragdefn.h"
#include "rtti.h"

#ifndef NDEBUG
    #include <stdio.h>
    #include "dbg.h"
    #include "pragdefn.h"

    static void _DUMP_CGRF( char *msg, SYMBOL sym ) {
        if( PragDbgToggle.callgraph ) {
            printf( msg, DbgSymNameFull( sym ) );
        }
    }
#else
    #define _DUMP_CGRF( msg, sym )
#endif

typedef struct vft_defn VFT_DEFN;
struct vft_defn {               // VFT_DEFN -- definition for VFT
    VFT_DEFN* next;             // - next in ring
    SYMBOL vft;                 // - symbol for vft
    CGFILE* cgfile;             // - virtual file containing definition
    CGFILE_INS location;        // - where to scan for definition
};

typedef struct scope_dtor SCOPE_DTOR;
struct scope_dtor               // SCOPE_DTOR -- delayed DTORing for a scope
{   SCOPE_DTOR* next;           // - next in ring
    SYMBOL dtor;                // - dtor
    DTOR_KIND kind;             // - type of dtor
    unsigned :0;                // - aligning
};

typedef struct                  // SCOPE_INFO -- scope information
{   SCOPE scope;                // - scope in question
    SCOPE_STATE state;          // - current state
    SCOPE_DTOR* dtoring;        // - ring of delayed dtoring
} SCOPE_INFO;

typedef struct                  // DTOR_SCOPE -- dtoring in a scope
{   unsigned opcode;            // - type of dtoring
    SYMBOL dtor;                // - dtor symbol
    SCOPE scope;                // - scope for dtoring
} DTOR_SCOPE;

static VFT_DEFN *vft_defs;          // ring of vftable defns
static carve_t carve_vft;           // carver for vft definitions
static CALLGRAPH* call_graph;       // call graph information
static unsigned max_inline_depth;   // maximum depth of inlining
static unsigned oe_size;            // size for inlining static functions

static struct {
    unsigned    inline_recursion:1; // TRUE ==> inline recursion allowed
    unsigned    any_state_tables:1; // TRUE ==> state tables somewhere
    unsigned    only_once_found :1; // TRUE ==> ->once_inl fn somewhere
//  unsigned    not_inlined_set :1; // TRUE ==> not_inline set somewhere
} callGraphFlags;

typedef enum                    // TCF -- types of functions
{   TCF_MOD_INIT                // - module-init function
,   TCF_INLINE                  // - inline function
,   TCF_STATIC                  // - static, non-member
,   TCF_VFT                     // - virtual-function table
,   TCF_OTHER_FUNC              // - other function
,   TCF_NOT_FUNC                // - not a function
,   TCF_NULL                    // - NULL pointer
} TCF;

typedef struct                  // SCAN_INFO -- scanning information
{   CALLNODE* cnode;            // - current node
    CGFILE *file_ctl;           // - current file
    unsigned has_except_spec :1;// - TRUE ==> has except spec.
    SYMBOL scope_call_cmp_dtor; // - component dtor for scope-call optimization
    SYMBOL scope_call_tmp_dtor; // - temporary dtor for scope-call optimization
    SYMBOL scope_call_blk_dtor; // - scope dtor for scope-call optimization
    SCOPE curr_scope;           // - current scope
    unsigned func_dtm;          // - dtor method for function
} SCAN_INFO;

static void forceGeneration(    // FORCE CODE FILE TO BE GENERATED
    CALLNODE *node );           // - function in graph


#ifndef NDEBUG
    void CallGraphDump( void )
    {
        CgrfDump( call_graph );
    }

    static void _printScanInt( const char* msg, unsigned val )
    {
        if( PragDbgToggle.callgraph_scan ) {
            printf( msg, val );
        }
    }

#else
    #define _printScanInt( a, b )
#endif


ExtraRptCtr( ctr_funs_scanned );    // functions scanned
ExtraRptCtr( ctr_funs_rescanned );  // functions re-scanned
ExtraRptCtr( ctr_vfts_scanned );    // VFT's scanned
ExtraRptCtr( ctr_vfts_genned );     // VFT's generated
ExtraRptCtr( ctr_nodes_visited );   // nodes visited (measure of work)
ExtraRptCtr( ctr_gened );           // functions left after processing


static SYMBOL callNodeCaller(   // GET SYMBOL FOR CALLER FROM CALLNODE
    CALLNODE* cnode )           // - call node
{
    SYMBOL sym;                 // - caller symbol

    sym = cnode->base.object;
    return sym;
}


void CgrfMarkNodeGen(           // MARK NODE AS GEN-ED, IF REQ'D
    CALLNODE* cnode )           // - the node
{
    switch( cnode->dtor_method ) {
      case DTM_DIRECT :
        break;
      case DTM_DIRECT_SMALL :
      { SYMBOL func = callNodeCaller( cnode );
        if( NULL == func
         || ! SymIsDtor( func ) ) break;
      }
        // drops thru
      default :
        cnode->stab_gen = TRUE;
        break;
    }
}


static TCF cgbackFuncType(      // DETERMINE TYPE OF FUNCTION
    SYMBOL sym )                // - symbol
{
    TCF retn;                   // - type of function

    if( sym == NULL ) {
        retn = TCF_MOD_INIT;
    } else if( ! SymIsFunction( sym ) ) {
        if( SymIsVft( sym ) ) {
            retn = TCF_VFT;
        } else {
            retn = TCF_NOT_FUNC;
        }
    } else if( ! SymIsInitialized( sym ) ) {
        retn = TCF_OTHER_FUNC;
    } else if( SymIsInline( sym ) ) {
        retn = TCF_INLINE;
    } else if( oe_size != 0 ) {
        retn = TCF_STATIC;
    } else if( SymIsRegularStaticFunc( sym ) ) {
        retn = TCF_STATIC;
    } else {
        retn = TCF_OTHER_FUNC;
    }
    return retn;
}


static CGFILE* nodeCgFile(      // GET CGFILE FOR NODE
    CALLNODE* node )            // - the node
{
    CGFILE* retn;               // - the CGFILE

    retn = node->cgfile;
    if( retn == NULL ) {
        retn = CgioLocateFile( node->base.object );
        node->cgfile = retn;
    }
    return retn;
}


static boolean funcInlineable(  // DETERMINE IF FUNCTION INLINE-ABLE
    SYMBOL sym )                // - function symbol
{
    AUX_INFO *pragma;

    DbgAssert( sym != NULL );
    if( max_inline_depth == 0 ) {
        // no inlining allowed
        return( FALSE );
    }
    if( ! SymIsInitialized( sym ) ) {
        // sym has no code to inline
        return( FALSE );
    }
    if( SymIsUninlineable( sym ) ) {
        // sym has been tagged as not being inlineable
        // e.g., contains _asm code that references auto vars
        return( FALSE );
    }
    if( SymIsEllipsisFunc( sym ) ) {
        // function could not access parms through <stdarg.h> if inlined
        return( FALSE );
    }
    // used to have: if( TypeHasPragma( sym->sym_type ) ) (why? AFS)
    pragma = TypeHasPragma( sym->sym_type );
    if( pragma != NULL ) {
        if( ! PragmaOKForInlines( pragma ) ) {
            // something weird and system specific would cause a problem
            return( FALSE );
        }
    }
    return( TRUE );
}


static boolean oeInlineable(    // DETERMINE IF /oe CAN INLINE THE FUNCTION
    SYMBOL sym,                 // - symbol for node
    CGFILE *cgfile )            // - code gen file for function
{
    boolean retn;               // - TRUE ==> CAN BE /oe inlined

    if( funcInlineable( sym ) ) {
        if( cgfile == NULL ) {
            retn = FALSE;
        } else if( cgfile->oe_inl ) {
            retn = TRUE;
        } else {
            retn = FALSE;
        }
    } else {
        retn = FALSE;
    }
    return retn;
}


static boolean canBeOeInlined(  // DETERMINE IF /oe CAN INLINE THE FUNCTION
    CALLNODE* node )            // - node for function
{
    return oeInlineable( node->base.object, nodeCgFile( node ) );
}


static boolean shouldBeInlined( // DETERMINE IF INLINING AN INLINABLE FN IS OK
    SYMBOL sym )                // - function symbol
{
    FN_CTL *fctl;               // - current file control

    if( CgBackInlinedDepth() >= max_inline_depth ) {
        return( FALSE );
    }
    fctl = FnCtlTop();
    if( fctl == NULL || SymIsThunk( fctl->func ) ) {
        return FALSE;
    }
    if( ! callGraphFlags.inline_recursion ) {
        for( ; fctl != NULL; fctl = FnCtlPrev( fctl ) ) {
            if( sym == fctl->func ) return( FALSE );
        }
    }
    return( TRUE );
}


static CALLNODE* addNode(       // ADD A CALL NODE
    SYMBOL sym )                // - symbol for node
{
    CALLNODE* node = CgrfAddFunction( call_graph, sym );
    switch( cgbackFuncType( sym ) ) {
      case TCF_VFT :
        node->is_vft = TRUE;
        break;
      case TCF_INLINE :
        node->inline_fun = TRUE;
        if( funcInlineable( sym ) ) {
            node->inlineable = TRUE;
            sym->flag |= SF_CG_INLINEABLE;
        }
        break;
      case TCF_OTHER_FUNC :
      case TCF_STATIC :
        if( funcInlineable( sym ) ) {
            node->inlineable = TRUE;
            if( oe_size > 0 ) {
                node->inlineable_oe = canBeOeInlined( node );
                if( node->inlineable_oe ) {
                    sym->flag |= SF_CG_INLINEABLE;
                }
            }
        }
        break;
      case TCF_MOD_INIT :
        break;
      DbgDefault( "addNode -- bad type" );
    }
    return node;
}


static CALLNODE *addCallee(     // ADD CALL TO CALL GRAPH
    SYMBOL callee )             // - symbol called
{
    CALLNODE *retn;             // - node for callee
    SYMBOL *pfun;               // - addr[ stacked symbol ]

    retn = addNode( callee );
    if( ( retn->refs == 0 ) && ( retn->addrs == 0 ) ) {
        switch( cgbackFuncType( callee ) ) {
          case TCF_VFT :
            pfun = (SYMBOL*)VstkPush( &call_graph->calls );
            *pfun = callee;
            break;
          case TCF_INLINE :
          case TCF_STATIC :
            pfun = (SYMBOL*)VstkPush( &call_graph->calls );
            *pfun = callee;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?