optimize.c

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

C
474
字号
}


static  void    PushInsForward( block *blk ) {
/*********************************************
    Try pushing down each instruction in the program.
*/

    instruction *ins;
    instruction *prev;
    instruction *next;

    ins = blk->ins.hd.prev;            /* move backwards through instructions*/
    for(;;) {
        if( ins->head.opcode == OP_BLOCK ) break;
        prev = ins->head.prev;

        next = CanMoveAfter( ins );
        if( next != NULL ) {

            /*   Remove 'ins' from its current position*/

            ins->head.next->head.prev = ins->head.prev;
            ins->head.prev->head.next = ins->head.next;

            /*   Link 'ins' before 'next'*/

            ins->head.prev = next->head.prev;
            next->head.prev = ins;
            ins->head.prev->head.next = ins;
            ins->head.next = next;
        }
        ins = prev;
    }
}


extern  bool    SameThing( name *x, name *y ) {
/**********************************************
    returns TRUE if "x" and "y" are the same thing. IE: N_MEMORY
    names which are associated with the same front end symbol or
    N_TEMP names which are aliases of each other. Two temporaries
    which are "stackable" are considered to be the same thing
    since they may (probably will) both end up on the 8087 stack.
*/

    if( x == y ) return( TRUE );
    if( x == NULL || y == NULL ) return( FALSE );
    if( FPIsStack( x ) && FPIsStack( y ) ) return( TRUE );
    if( x->n.class == N_MEMORY
     && y->n.class == N_MEMORY
     && x->v.symbol == y->v.symbol ) return( TRUE );
    if( x->n.class == N_TEMP && y->n.class == N_TEMP ) {
        if( x->t.v.id != y->t.v.id ) return( FALSE );
        if( !( x->t.temp_flags & ALIAS )
         && !( y->t.temp_flags & ALIAS ) ) return( FALSE );
        return( TRUE );
    }
    return( FALSE );
}


extern  void    DeadTemps() {
/****************************
    Using the information contained in each N_TEMP, delete any instruction
    whose result is a temporary that isnt used again. This is only a very
    crude hack of dead code, since it only gets temporaries which are local
    to a basic block and are only defined. Its designed to get rid of
    dummy instructions generated to preserve the value of an assignment
    operator. For example, *x = *y generates:
        MOV     [y] => [x]
        MOV     [x] => temp     <- this usually doesn't get used later
*/

    block       *blk;
    instruction *ins;
    instruction *next;

    blk = HeadBlock;
    while( blk != NULL ) {
        ins = blk->ins.hd.next;
        while( ins->head.opcode != OP_BLOCK ) {
            next = ins->head.next;
            if( SideEffect( ins ) == FALSE
             && _IsntIns( ins, SIDE_EFFECT )
             && ins->result != NULL
             && ins->result->n.class == N_TEMP
             && ( ins->result->v.usage
               &(USE_ADDRESS|HAS_MEMORY|USE_WITHIN_BLOCK|USE_IN_ANOTHER_BLOCK) )
               == EMPTY ) {
                FreeIns( ins );
            }
            ins = next;
        }
        blk = blk->next_block;
    }
}


static  bool    IsDeadIns( block *blk, instruction *ins, instruction *next ) {
/*****************************************************************************
    returns TRUE if an instruction is assigning to a name which is not
    live immediately following instruction "ins".
*/

    conflict_node       *conf;
    name                *op;

    op = ins->result;
    if( op == NULL ) return( FALSE );
//  if( op->n.class != N_TEMP ) return( FALSE );
    if( op->v.usage & USE_ADDRESS ) return( FALSE );
    if( SideEffect( ins ) ) return( FALSE );
    conf = FindConflictNode( op, blk, ins );
    if( conf == NULL ) return( FALSE );
    if( _LBitEmpty( conf->id.within_block )
     && _GBitEmpty( conf->id.out_of_block ) ) {
         return( FALSE );
     }
    if( _LBitOverlap( conf->id.within_block, next->head.live.within_block ) ) {
        return( FALSE );
    }
    if( _GBitOverlap( conf->id.out_of_block, next->head.live.out_of_block ) ) {
        return( FALSE );
    }
    return( TRUE );
}


extern  void    AxeDeadCode() {
/******************************
    This is like DeadTemps, but it uses the live information in order
    to discover whether an instruction is assigning to a variable that
    dies immediately following. If we change anything here, we redo
    the live information (that's not very expensive).
*/

/* delete instructions which assign to temporaries which will not be*/
/* used again before they are reassigned (ie: are not live after the instruction*/

    block               *blk;
    instruction         *ins;
    instruction         *next;
    instruction         *kill;
    bool                change;

/* Reuse field, it's useless for killed instruction */
#define _INS_KILL_LINK( ins )  ( ins )->u2.cse_link

    for(;;) {
        kill = NULL;
        change = FALSE;
        blk = HeadBlock;
        while( blk != NULL ) {
            ins = blk->ins.hd.next;
            while( ins->head.opcode != OP_BLOCK ) {
                next = ins->head.next;
                if( IsDeadIns( blk, ins, next ) ) {
                    ins->result = NULL;
                    change = TRUE;
                    if( _IsntIns( ins, SIDE_EFFECT ) ) {
                       /*
                        * 2005-05-18 RomanT
                        * Do not free instruction immediately, or conflict
                        * edges will point to nowhere. Add them to kill list.
                        */
                        _INS_KILL_LINK( ins ) = kill;
                        kill = ins;
                    } else if( _OpIsCondition( ins->head.opcode ) ) {
                        _SetBlockIndex( ins, NO_JUMP, NO_JUMP );
                    }
                }
                ins = next;
            }
            blk = blk->next_block;
        }
        if( change == FALSE ) break;
        FreeConflicts();
        /* Now it's safe to free instructions without problems with edges */
        while ( kill ) {
            next = _INS_KILL_LINK( kill );
            FreeIns( kill );
            kill = next;
        }
        NullConflicts(EMPTY);
        FindReferences();
        MakeConflicts();
        MakeLiveInfo();
    }
}


extern  void    DeadInstructions() {
/***********************************
    This is called after register allocation. It frees up any
    instructions whose generate table says G_NO (don't generate me).
*/

    block       *blk;

    blk = HeadBlock;
    while( blk != NULL ) {
        FreeJunk( blk );
        blk = blk->next_block;
    }
}


extern  void    PushPostOps() {
/******************************
    This routine tries to push add and subtract instructions
    forward in the basic block. The reason for this is that
    it untangles post increment code allowing for copy propagation
    and code elimination. Take *x++ = *y++ for example

    Before:                     After:                  With copy propagation:

    MOV x => t1                 MOV x => t1             MOV x => t1 (useless)
    MOV y => t2                 MOV y => t2             MOV y => t2 (useless)
    ADD x, 1 => x               MOV [t2] => [t1]        MOV [y] => [x]
    ADD y, 1 => y               ADD x,1 => x            ADD x,1 => x
    MOV [t2] => [t1]            ADD y,1 => y            ADD y,1 => y
*/

/*    Perform instruction optimizations*/

    block       *blk;

    blk = HeadBlock;
    while( blk != NULL ) {
        PushInsForward( blk );
        blk = blk->next_block;
    }
    PropagateMoves();
    Renumber();
}

⌨️ 快捷键说明

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