i86ldstr.c

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

C
622
字号
    new_l->operands[ 1 ] = (void *)new_h;
    new_l->ins_flags |= INS_SPLIT;
    new_h->ins_flags |= INS_SPLIT;
    SuffixIns( ins, new_l );
    SuffixIns( ins, new_h );
    FreeIns( ins );

    new_h = MakeGeneratable( new_h );
    new_l = MakeGeneratable( new_l );
    return( TRUE );
}

static  void    RestoreMem16Move( instruction *ins )
/***************************************************
    Put a 16-bit move back together in case we were
    unable to schedule the one-byte moves into being
    faster. See comment about cheesiness above.
*/
{
    instruction *other;
    hw_reg_set  full;

    if( ins->head.next == (instruction *)ins->operands[ 1 ] ) {
        other = ins->head.next;
    } else if( ins->head.prev == (instruction *)ins->operands[ 1 ] ) {
        other = ins->head.prev;
    } else {
        return;
    }
    if( ( other->ins_flags & INS_SPLIT ) == EMPTY ) return;
    if( ins->result->n.class == N_REGISTER && other->result->n.class == N_REGISTER ) {
        full = HW_EMPTY;
        HW_TurnOn( full, other->result->r.reg );
        HW_TurnOn( full, ins->result->r.reg );
        ins->result = AllocRegName( full );
        ins->type_class = U2;
        FreeIns( other );
    }
}

static  bool    FixMem16Moves( void )
/******************************
    Look for 16-bit mem moves and turn them into two 1-byte
    mem moves, so as to escape the dreaded size override. If
    we are unable to schedule them, we will crunch them back
    up in LdStCompress. We want to do this as a separate pass
    so that we can fix moves generated by LdStAlloc.
*/
{
    block       *blk;
    instruction *ins;
    bool        changed;
    instruction *next;

    if( OptForSize != 0 ) return( FALSE );
    if( !_CPULevel( CPU_586 ) ) return( FALSE );
    changed = FALSE;
    for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) {
        for( ins=blk->ins.hd.next; ins->head.opcode!=OP_BLOCK; ins=next ) {
            next = ins->head.next;      /* list is shifting underneath us */
            if( ins->head.opcode == OP_MOV && TypeClassSize[ ins->type_class ] == 2 ) {
                switch( ins->operands[ 0 ]->n.class ) {
                case N_MEMORY:
                case N_INDEXED:
                case N_TEMP:
                    if( ins->ins_flags & INS_SPLIT ) {
                        changed |= SplitMem16Move( ins );
                    }
                default:
                    break;
                }
            }
        }
    }
    return( changed );
}

static  void    CompressMem16Moves( void )
/***********************************
*/
{
    block       *blk;
    instruction *ins;

    if( !_CPULevel( CPU_586 ) ) return;
    for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) {
        for( ins = blk->ins.hd.next; ins->head.opcode != OP_BLOCK; ins = ins->head.next ) {
            RestoreMem16Move( ins );
        }
    }
}
#else
static  bool    FixMem16Moves( void ) { return( FALSE ); }
static  void    CompressMem16Moves( void ) {}
#endif



extern  bool    LdStAlloc( void )
/*******************************

    Look for non-move operations with memory operands and change them
    into RISC style load/store instructions. This helps on the 486 and
    up because of instruction scheduling. Return a boolean saying whether
    anything got twiddled so the register scoreboarder can be run again.

    This routine also required for optimization of assignment
    of one copy of same constant to multiple memory locations using
    temporary register.
*/
{
    block       *blk;
    instruction *ins;
    instruction *next;
    bool        changed;

    RoverByte = NULL;
    RoverWord = NULL;
    RoverDouble = NULL;

    /* 2006-04-25 RomanT:
       Run RISCifier for all modes, but sometimes (depending on CPU and
       optimization) prefer shorter non-RISC version of instructions.
    */
    PreferSize = FALSE;
    if( OptForSize > 50 ) {
        PreferSize = TRUE;
    }
    if( !_CPULevel( CPU_486 ) ) {
        PreferSize = TRUE;
    }

#if 0  /* You can optionally disable riscifer when optimizing for size */
    if (PreferSize) return FALSE;
#endif

    changed = FALSE;
    for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) {
        for( ins=blk->ins.hd.next; ins->head.opcode!=OP_BLOCK; ins=next ) {
            next = ins->head.next;      /* list is shifting underneath us */
            if( LoadStoreIns( ins ) ) {
                UpdateLive( blk->ins.hd.next, blk->ins.hd.prev );
                changed = TRUE;
            }
        }
    }
    changed |= FixMem16Moves();
    return( changed );
}

static bool     CanCompressResult( instruction *ins,
                                   name *prev_op0, instruction *next,
                                   name **presult, name **popnd )
{
    int         i;

    if( presult == NULL ) {
        return FALSE;
    }
    if( HW_Ovlap( (*presult)->r.reg, next->head.next->head.live.regs ) ) {
        return FALSE;
    }
    if( popnd != NULL ) {
        if( *popnd != *presult ) return FALSE;
        if( next->result != prev_op0 ) return FALSE;
    } else {
        for( i = 0; i < ins->num_operands; ++i ) {
            if( ins->operands[i]->n.class != N_REGISTER ) {
                continue;
            }
            if( HW_Ovlap( ins->operands[i]->r.reg, ins->result->r.reg ) ) {
                return FALSE;
            }
        }
    }
    return TRUE;
}

static void     CompressIns( instruction *ins )
/**************************************************

    See if a RISCified instruction 'ins' is still in CISCifyable form and
    do it to it.
*/
{
    instruction *next;
    instruction *prev;
    name        *prev_op0;
    name        **presult;
    name        **popnd;
    name        **preplace;
    name        *replacement;
    int         i;
    int         num_op;

    if( !(ins->ins_flags & INS_RISCIFIED) ) return;
    switch( ins->head.opcode ) {
    case OP_PUSH:
    case OP_POP:
        /* If size preferable then push must be compacted */
        if( PreferSize ) break;
        /* It's better to use a register for PUSH/POP on a 486 */
        if( _CPULevel( CPU_486 ) ) return;
    default:
        break;
    }
    next = ins->head.next;
    if( next->head.opcode != OP_MOV || next->operands[0]->n.class != N_REGISTER ) {
        next = NULL;
    }
    prev = ins->head.prev;
    prev_op0 = prev->operands[0];
    if( prev->head.opcode != OP_MOV || prev->result->n.class != N_REGISTER ) {
        /* 2006-10-14 RomanT
         * Special case: "MOV REG, 0" usually reduced to "XOR REG, REG",
         * changing opcode and confusing deriscifier. XOR is shorter then
         * non-optimized 16- or 32-bit MOV, but worse for 8-bit moves
         * (same size, two commands, extra register occupied).
         *
         * Handling these XOR's everywhere is boring. It must be rewriten
         * in some other way. May be we shall instroduce G_SMARTMOV which must
         * be resolved to XOR/AND 0/OR -1/XOR+INC only during generation
         * of machine code.
         */
        if ( prev->head.opcode == OP_XOR            &&
             prev_op0 == prev->operands[1]          &&
             TypeClassSize[ prev->type_class ] == 1
           ) {
            prev_op0 = AllocIntConst( 0 );  /* fake "MOV RESULT, 0" */
        }
        else {
            prev = NULL;
        }
    }

    presult = NULL;
    popnd = NULL;
    if( next != NULL && ins->result == next->operands[0] ) {
        presult = &ins->result;
    }
    if( prev != NULL ) {
        // 2005-04-05 RomanT
        // Do not use ins->num_operands here, otherwise we'll falsely trigger
        // compression for segment operand of instruction which we shouldn't.
        // (bug #442)
        num_op = NumOperands( ins );
        for( i = 0; i < num_op; ++i ) {
            if( prev->result == ins->operands[i] ) {
                popnd = &ins->operands[i];
            }
        }
    }
    // 2006-05-19 RomanT
    // Even if compression of result failed, we must try to compress operands
    if( CanCompressResult( ins, prev_op0, next, presult, popnd ) ) {
        replacement = next->result;
        preplace = presult;
    } else {
        presult = NULL; // Forget about result (don't free ins below!)
        if( popnd == NULL ) return;
        // make sure that the REG is not used in any operands besides
        // the one which we are thinking of replacing BBB - Dec 4, 1993
        for( i = 0; i < ins->num_operands; i++ ) {
            if( popnd == &ins->operands[ i ] ) continue;
            if( ins->operands[ i ]->n.class != N_REGISTER ) continue;
            if( HW_Ovlap( ins->operands[ i ]->r.reg, (*popnd)->r.reg ) ) {
                return;
            }
        }
        if( HW_Ovlap( (*popnd)->r.reg, ins->head.next->head.live.regs ) ) {
            return;
        }
        replacement = prev_op0;
        preplace = popnd;
    }
    if( !ChangeIns( ins, replacement, preplace, CHANGE_GEN | CHANGE_ALL ) ) return;
    if( presult != NULL ) {
        DupSeg( next, ins );
        FreeIns( next );
    }
    if( popnd != NULL ) {
        DupSeg( prev, ins );
        FreeIns( prev );
    }
    UpdateLive( ins->head.prev, ins );
}


extern  void    LdStCompress( void )
/**********************************

    Compress any load/store sequences generated by LdStAlloc back
    into memory ops if no optimizations made use of them.
*/
{
    block       *blk;
    instruction *ins;

    /* Note: LdStAlloc() must be called first to set PreferSize variable */

    CompressMem16Moves();
    for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) {
        ins = blk->ins.hd.next;
        while( ins->head.opcode != OP_BLOCK ) {
            CompressIns( ins );
            ins = ins->head.next;
        }
    }
    DeadInstructions();
}

⌨️ 快捷键说明

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