varusage.c

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

C
486
字号
/****************************************************************************
*
*                            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:  Variable/memory usage analysis.
*
****************************************************************************/


#include "standard.h"
#include "coderep.h"
#include "opcodes.h"
#include "sysmacro.h"
#include "conflict.h"
#include "hwreg.h"

extern  name            *DeAlias(name*);

extern    block         *HeadBlock;
extern    name          *Names[];
extern    conflict_node *ConfList;
extern    bool          BlockByBlock;


static  void    Use( name *op, block *blk, var_usage usage )
/***********************************************************
    Mark "op" as used in "blk".  assume that if it hasn't already been
    defined in this block, that it must be USE_IN_ANOTHER_BLOCK.  "usage"
    may be set to USE_ADDRESS indicating that we are using the address
    of the name.
*/
{
    if( op->n.class == N_CONSTANT && op->c.const_type == CONS_TEMP_ADDR ) {
        Use( (name*)op->c.value, blk, USE_ADDRESS );
        return;
    }
    if( op->n.class == N_TEMP ) {
        op = DeAlias( op );
    } else if( op->n.class != N_MEMORY ) {
        return;
    }
    if( op->v.block_usage & DEF_WITHIN_BLOCK ) {
        op->v.block_usage |= USE_WITHIN_BLOCK;
    } else {
        op->v.block_usage |= USE_IN_ANOTHER_BLOCK;
        if( op->v.conflict != NULL ) {
            _GBitTurnOn( blk->dataflow->use,
                    op->v.conflict->id.out_of_block );
        }
    }
    op->v.block_usage |= usage;
}


static  bool    CoveringDefinitions( name *op )
/**********************************************
    If we are only defining a piece of "op", we check all of its aliases
    to see if they have been defined in this block as well.  Only if all
    the definitions cause the entire name to be redefined do we mark the
    master symbol table entry for the name as "DEF_WITHIN_BLOCK" and
    flip on its bit in dataflo->def.
*/
{
    name        *alias;
    int         i;
    uint        loc;
    bool        covered[MAX_POSSIBLE_REG+1];

    if( op->n.size > MAX_POSSIBLE_REG ) return( FALSE );
    i = op->n.size;
    while( --i >= 0 ) {
        covered[ i ] = FALSE;
    }
    alias = op->t.alias;
    while( alias != op ) {
        if( alias->v.block_usage & DEF_WITHIN_BLOCK ) {
            loc = alias->v.offset - op->v.offset;
            i = alias->n.size;
            while( --i >= 0 ) {
                if( loc < sizeof( covered ) ) covered[ loc ] = TRUE;
                ++loc;
            }
        }
        alias = alias->t.alias;
    }
    i = op->n.size;
    while( --i >= 0 ) {
        if( covered[ i ] == FALSE ) return( FALSE );
    }
    return( TRUE );
}


static  void    Define( name *op, block *blk )
/*********************************************
    Mark "op" as defined within "blk".
*/
{
    name        *actual;

    actual = op;
    actual->v.block_usage |= DEF_WITHIN_BLOCK;
    if( op->n.class == N_TEMP ) op = DeAlias( op );
    if( op->v.block_usage & USE_IN_ANOTHER_BLOCK ) return;
    if( actual != op && CoveringDefinitions( op ) == FALSE ) return;
    op->v.block_usage |= DEF_WITHIN_BLOCK;
    if( op->v.conflict == NULL ) return;
    _GBitTurnOn( blk->dataflow->def, op->v.conflict->id.out_of_block );
}


static  void    UseDefGlobals( block *blk )
/******************************************
    If a call instruction is encountered, all N_MEMORY names (visible
    outside this procedure), could be both used and defined by the call.
*/
{
    conflict_node       *conf;
    var_usage           usage;

    conf = ConfList;
    while( conf != NULL ) {
        if( conf->name->n.class == N_MEMORY ) {
            usage = conf->name->v.block_usage;
            Use( conf->name, blk, EMPTY );
            Define( conf->name, blk );
            _GBitTurnOn( blk->dataflow->def, conf->id.out_of_block );
            if( ( usage & DEF_WITHIN_BLOCK ) == EMPTY ) {
                _GBitTurnOn( blk->dataflow->use, conf->id.out_of_block );
            }
        }
        conf = conf->next_conflict;
    }
}


static void TransferBlockUsage( name *op )
/*****************************************
    Never have both USE_WITHIN_BLOCK and USE_IN_ANOTHER_BLOCK set.
*/
{
    op->v.usage |= op->v.block_usage;
    if( op->v.usage & USE_IN_ANOTHER_BLOCK ) {
        op->v.usage &= ~ USE_WITHIN_BLOCK;
    }
    op->v.block_usage = EMPTY;
}


static void TransferOneTempBlockUsage( name *op )
/************************************************
    see TransferTempBlockUsage ^
*/
{
    name        *alias;

    if( op->n.class == N_CONSTANT && op->c.const_type == CONS_TEMP_ADDR ) {
        TransferOneTempBlockUsage( op->c.value );
    } else if( op->n.class == N_INDEXED ) {
        TransferOneTempBlockUsage( op->i.index );
        if( HasTrueBase( op ) ) {
            TransferOneTempBlockUsage( op->i.base );
        }
    } else if ( op->n.class == N_TEMP ) {
        alias = op->t.alias;
        for( ;; ) {
            TransferBlockUsage( alias );
            if( alias == op ) break;
            alias = alias->t.alias;
        }
    }
}


static void TransferTempBlockUsage( block *blk )
/***********************************************
    Traverse the block "blk", and for each variable referenced by an
    instruction within block, Make sure that USE_WITHIN_BLOCK and
    USE_IN_OTHER_BLOCK are not on simultaneously for each variable and
    all of its aliases.  We traverse the block rather than Names[N_TEMP]
    since running down the list of temps could be very expensive (if
    long).  Blocks on the other hand are always reasonably short
*/
{
    instruction *ins;
    int         i;

    ins = blk->ins.hd.next;
    while( ins->head.opcode != OP_BLOCK ) {
        i = ins->num_operands;
        while( --i >= 0 ) {
            TransferOneTempBlockUsage( ins->operands[ i ] );
        }
        if( ins->result != NULL ) {
            TransferOneTempBlockUsage( ins->result );
        }
        ins = ins->head.next;
    }
}


static  void    TransferAllMemBlockUsage( void )
/***********************************************
    Like TransferTempBlockUsage.
*/
{
    name        *mem;

    for( mem = Names[N_MEMORY]; mem != NULL; mem = mem->n.next_name ) {
        TransferBlockUsage( mem );
    }
}


static void TransferOneMemBlockUsage( name *op )
/***********************************************
    see TransferMemBlockUsage ^
*/
{
    if( op->n.class == N_INDEXED ) {
        TransferOneMemBlockUsage( op->i.index );

⌨️ 快捷键说明

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