i86enc.c

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

C
2,335
字号
    if( ins->ins_flags & INS_CC_USED ) return( TRUE );
    if( ins->result == NULL ) return( TRUE );
    switch( ins->result->n.class ) {
    case N_TEMP:
        /* it's OK to store a DWORD into a WORD temp because there's always
           two bytes of slack on the stack */
        if( ins->result->t.alias != ins->result ) return( TRUE );
        break;
    case N_REGISTER:
        /* check that it's OK to trash high word of register */
        next = ins->head.next;
        if( next == NULL ) return( TRUE );
        result_reg = ins->result->r.reg;
        full_reg = FullReg( result_reg );
        HW_TurnOff( full_reg, result_reg );
        if( HW_Ovlap( full_reg, next->head.live.regs ) ) return( TRUE );
        break;
    default:
        return( TRUE );
    }
    for( i = ins->num_operands-1; i >= 0; --i ) {
        /* Could be smarter here and allow N_MEMORY,N_INDEXED if
           they're in DGROUP */
        switch( ins->operands[i]->n.class ) {
        case N_TEMP:
        case N_REGISTER:
        case N_CONSTANT:
            break;
        default:
            return( TRUE );
        }
    }
    ins->type_class = U4; /* get correct size of constants */
    return( FALSE );
}
#endif


static  bool    LayOpndSize( instruction *ins, gentype gen ) {
/*************************************************************
    Generate an operand size prefix if the instruction needs it
    (Eg: MOV    AX,DX need it in a USE32 segment)
*/

#if _TARGET & _TARG_80386
    switch( ins->head.opcode ) {
    case OP_CONVERT: /* these ones handle themselves */
    case OP_CALL:
    case OP_CALL_INDIRECT:
    case OP_SELECT:
        return( FALSE );
        break;
    default:
        switch( gen ) {
#if _TARGET & _TARG_IAPX86
        case G_POW2DIV_286:
#endif
        case G_SR:
        case G_RS:
        case G_MS1:
        case G_SM1:
        case G_SEG_SEG:
        case G_SEGR1:
        case G_POW2DIV:
        case G_DIV2:
            return( FALSE );
        default:
            break;
        }
        if( _IsTargetModel( USE_32 ) ) {
            if( ins->type_class == U2 || ins->type_class == I2 ) {
                if( NeedOpndSize( ins ) ) {
                    AddToTemp( M_OPND_SIZE );
                    return( TRUE );
                }
            }
        } else {
            if( ins->type_class == U4
             || ins->type_class == I4
             || ins->type_class == FS ) {
                AddToTemp( M_OPND_SIZE );
                return( TRUE );
            }
        }
        return( FALSE );
    }
#else
    gen = gen;
    switch( ins->head.opcode ) {
    case OP_PUSH:
        if( ( gen == G_C1 || gen == G_M1 ) && ins->type_class == I4 ) {
            AddToTemp( M_OPND_SIZE );
            return( TRUE );
        }
        break;
    case OP_MOV:
        if( ins->type_class == U4 || ins->type_class == I4 ) {
            if( ( gen == G_MOVMC ) ) {
                AddToTemp( M_OPND_SIZE );
                return( TRUE );
            }
        }
        break;
    default:
        break;
    }
    return( FALSE );
#endif
}

#if 1
static  void    DoP5RegisterDivide( instruction *ins ) {
/******************************************************/

    int                 i;
    byte                reverse;
    byte                pop;
    byte                dest;
    int                 ins_key;
    label_handle        lbl;
    label_handle        lbl_2;
    oc_jcond            temp;

    lbl = AskForNewLabel();
    lbl_2 = AskForNewLabel();

    temp.op.class = OC_JCOND;
    temp.op.class |= ATTR_SHORT;
    temp.op.objlen = OptInsSize( OC_JCOND, OC_DEST_NEAR );
    temp.op.reclen = sizeof( oc_jcond );
    temp.cond = 4;
    temp.handle = lbl;
    InputOC( (any_oc *)&temp );
    i = FPRegTrans( ins->operands[ 0 ]->r.reg );
    reverse = FALSE;
    pop = FALSE;
    dest = FALSE;
    switch( ins->u.gen_table->generate ) {
    case G_RRFBIN:
        reverse = TRUE;
        break;
    case G_RNFBIN:
        break;
    case G_RRFBINP:
        reverse = TRUE;
        pop = TRUE;
        dest = TRUE;
        break;
    case G_RNFBINP:
        pop = TRUE;
        dest = TRUE;
        break;
    case G_RRFBIND:
        reverse = TRUE;
        dest = TRUE;
        break;
    case G_RNFBIND:
        dest = TRUE;
        break;
    }
    ins_key = ( pop & 1 ) | ( ( reverse & 1 ) << 1 ) | ( ( dest & 1 ) << 2 );
    ins_key |= ( i & 0x07 ) << 3;
    // je ok
    _Code;
    _Next;
    // push [e]ax
    LayOpbyte( 0x50 );
    _Next;
    // mov #cons -> [e]ax
    LayOpbyte( 0xb8 );
    #if _TARGET & _TARG_80386
        AddWData( ins_key, U4 );
    #else
        AddWData( ins_key, U2 );
    #endif
    _Emit;
    // call __fdiv_fpr
    RTCall( RT_FDIV_FPREG, 0 );
    _Code;
    // pop [e]ax
    LayOpbyte( 0x58 );
    _Emit;
    GenJumpLabel( lbl_2 );
    CodeLabel( lbl, 0 );
    _Code;
    LayInitial( ins, ins->u.gen_table->generate );
    LayOpndSize( ins, ins->u.gen_table->generate );
    LayST( ins->operands[ 0 ] );
    _Emit;
    CodeLabel( lbl_2, 0 );
    GenKillLabel( lbl );
    GenKillLabel( lbl_2 );
}

#if _TARGET & _TARG_80386
    extern type_length StackDepth;
#endif

static  void    DoP5MemoryDivide( instruction *ins ) {
/****************************************************/

    oc_jcond            temp;
    int                 rtindex;
    label_handle        lbl;
    label_handle        lbl_2;
    name                *high;
    name                *low;
#if !(_TARGET & _TARG_80386)
    name                *h;
    name                *l;
#endif
    name                *seg;

    lbl = AskForNewLabel();
    lbl_2 = AskForNewLabel();

    temp.op.class = OC_JCOND;
    temp.op.class |= ATTR_SHORT;
    temp.op.objlen = OptInsSize( OC_JCOND, OC_DEST_NEAR );
    temp.op.reclen = sizeof( oc_jcond );
    temp.cond = 4;
    temp.handle = lbl;
    InputOC( (any_oc *)&temp );

    seg = NULL;
    if( ins->num_operands > NumOperands( ins ) ) {
        seg = ins->operands[ ins->num_operands - 1 ];
    }

    _Code;
    switch( ins->operands[ 0 ]->n.name_class ) {
    case FS:
    #if _TARGET & _TARG_80386
        if( seg != NULL ) GenSeg( seg->r.reg );
        LayOpword( 0x30ff );
        LayModRM( ins->operands[ 0 ] );
    #else
        high = HighPart( ins->operands[ 0 ], U2 );
        low = LowPart( ins->operands[ 0 ], U2 );
        if( seg != NULL ) GenSeg( seg->r.reg );
        LayOpword( 0x30ff );
        LayModRM( high );
        _Next;
        if( seg != NULL ) GenSeg( seg->r.reg );
        LayOpword( 0x30ff );
        LayModRM( low );
    #endif
        if( ins->u.gen_table->generate == G_MRFBIN ) {
            rtindex = RT_FDIV_MEM32R;
        } else {
            rtindex = RT_FDIV_MEM32;
        }
        break;
    case FD:
        high = HighPart( ins->operands[ 0 ], U4 );
        low = LowPart( ins->operands[ 0 ], U4 );
    #if _TARGET & _TARG_80386
        if( seg != NULL ) GenSeg( seg->r.reg );
        LayOpword( 0x30ff );
        LayModRM( high );
        _Next;
        StackDepth += WORD_SIZE;
        if( seg != NULL ) GenSeg( seg->r.reg );
        LayOpword( 0x30ff );
        LayModRM( low );
        StackDepth -= WORD_SIZE;
    #else
        h = HighPart( high, U2 );
        l = LowPart( high, U2 );
        if( seg != NULL ) GenSeg( seg->r.reg );
        LayOpword( 0x30ff );
        LayModRM( h );
        _Next;
        if( seg != NULL ) GenSeg( seg->r.reg );
        LayOpword( 0x30ff );
        LayModRM( l );
        _Next;
        h = HighPart( low, U2 );
        l = LowPart( low, U2 );
        if( seg != NULL ) GenSeg( seg->r.reg );
        LayOpword( 0x30ff );
        LayModRM( h );
        _Next;
        if( seg != NULL ) GenSeg( seg->r.reg );
        LayOpword( 0x30ff );
        LayModRM( l );
        _Next;
    #endif
        if( ins->u.gen_table->generate == G_MRFBIN ) {
            rtindex = RT_FDIV_MEM64R;
        } else {
            rtindex = RT_FDIV_MEM64;
        }
        break;
    default:
        rtindex = RT_FDIV_MEM64;
        _Zoiks( ZOIKS_114 );
    }
    _Emit;
    RTCall( rtindex, 0 );
    GenJumpLabel( lbl_2 );
    CodeLabel( lbl, 0 );
    _Code;
    if( seg != NULL ) {
        GenSeg( seg->r.reg );
    }
    LayInitial( ins, ins->u.gen_table->generate );
    LayOpndSize( ins, ins->u.gen_table->generate );
    LayMF( ins->operands[ 0 ] );
    LayModRM( ins->operands[ 0 ] );
    _Emit;
    CodeLabel( lbl_2, 0 );
    GenKillLabel( lbl );
    GenKillLabel( lbl_2 );
}

static  void    DoP5Divide( instruction *ins ) {
/***********************************************
    Emit a most disgusting sequence of code to
    test for the Pentium FDIV bug and call a
    runtime routine to correct it.
*/
    bool        used_ds = FALSE;

    _Code;
    LayOpbyte( 0x9c );  /* pushf */
    _Emit;
#if _TARGET & _TARG_80386
    StackDepth += WORD_SIZE;
#endif
    _Code;
    if( _IsTargetModel( FLOATING_DS ) ) {
        if( _IsTargetModel( FLOATING_SS ) ) {
            LayOpbyte( 0x1e );  // push ds
            AddByte( 0x50 );    // push ax
            _Emit;
            GenLoadDS();
            _Code;
            used_ds = TRUE;
        } else {
            AddToTemp( 0x36 );
        }
    }
    #if ( _TARGET & _TARG_80386 )
        LayOpword( 0x05f6 );
    #else
        LayOpword( 0x06f6 );
    #endif
    ILen += WORD_SIZE;
    DoLblRef( RTLabel( RT_BUGLIST - BEG_RTNS ), AskBackSeg(), 0, F_OFFSET );
    AddWData( 1, U1 );
    _Emit;
    if( used_ds ) {
        _Code;
        LayOpbyte( 0x58 );      // pop ax
        AddByte( 0x1f );        // pop ds
        _Emit;
    }
    switch( ins->u.gen_table->generate ) {
    case G_RRFBIN:
    case G_RNFBIN:
    case G_RRFBIND:
    case G_RNFBIND:
    case G_RRFBINP:
    case G_RNFBINP:
        // assuming G_RXFBINZ means
        //      X -> R (reverse) and N (normal)
        //      Z -> D (destination is argument)
        //        -> P (argument is popped)
        DoP5RegisterDivide( ins );
        break;
    case G_MRFBIN:
    case G_MNFBIN:
        DoP5MemoryDivide( ins );
    }
    _Code;
    LayOpbyte( 0x9d );  /* popf */
    _Emit;
#if _TARGET & _TARG_80386
    StackDepth -= WORD_SIZE;
#endif
}
#endif

extern  void    GenObjCode( instruction *ins ) {
/***********************************************
    Generate object code for the instruction "ins" based on gen_table->generate
*/

    gentype     gen;
    name        *result;
    name        *left = NULL;
    name        *right = NULL;
    int         i;
    bool        opnd_size;

    gen = ins->u.gen_table->generate;
    if( gen != G_NO ) {
    #if 1
        // fixme - should be _IsTargetModel
        if( _IsTargetModel( P5_DIVIDE_CHECK ) ) {
            if( ins->head.opcode == OP_DIV && _IsFloating( ins->type_class ) ) {
                DoP5Divide( ins );
                return;
            }
        }
    #endif
        result = ins->result;
        if( ins->num_operands != 0 ) {
            left = ins->operands[ 0 ];
            if( ins->num_operands != 1 ) {
                right = ins->operands[ 1 ];
            }
        }

        if (gen == G_MFSTRND)
        {
            /*
            68 3F 0C 00 00            push        0x00000c3f
            D9 7C 24 02               fnstcw      word ptr 0x2[esp]
            D9 2C 24                  fldcw       word ptr [esp]
            */

            _Code;
            AddByte(0x68);
            AddByte(0x3f);
            AddByte(0x0c);
            AddByte(0x00);
            AddByte(0x00);
            _Emit;

            _Code;
            AddByte(0xd9);
            AddByte(0x7c);
            AddByte(0x24);
            AddByte(0x02);
            _Emit;

            _Code;
            AddByte(0xd9);
            AddByte(0x2c);
            AddByte(0x24);
            _Emit;
        }

        _Code;
        LayInitial( ins, gen );
        i = ins->num_operands;
        --i;
        if( i >= NumOperands( ins ) ) {
            if( ins->operands[ i ]->n.class == N_REGISTER ) {
                GenSeg( ins->operands[ i ]->r.reg );
            } else {
                _Zoiks( ZOIKS_027 );
            }
        }
        opnd_size = LayOpndSize( ins, gen );
        switch( gen ) {
        case G_RC:
            LayRMRegOp( left );
            AddSWCons( ins->head.opcode, right, ins->type_class );
            break;
        case G_AC:
            ICur--;
            ILen--;
            IEsc--;
            AddWCons( right, ins->type_class );

⌨️ 快捷键说明

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