i87reg.c

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

C
817
字号
/***********************************************
    Turn op1 (operands[0]) of instruction "ins" into a variable of a
    type that can be used directly by an 8087 instruction like FLD or
    FILD.
*/

    name                *t;
    instruction         *new_ins;
    type_class_def      class;

    class = ins->base_type_class;
    switch( class ) {
    case U1:
    case I1:
        t = AllocTemp( I2 );
        new_ins = MakeConvert( ins->operands[ 0 ], t, I2, class );
        ins->base_type_class = I2;
        ins->operands[ 0 ] = t;
        MoveSegOp( ins, new_ins, 0 );
        PrefixIns( ins, new_ins );
        InMemory( NameConflict( ins, t ) );
        break;
    case U2:
        t = AllocTemp( I4 );
        new_ins = MakeConvert( ins->operands[ 0 ], t, I4, class );
        ins->base_type_class = I4;
        ins->operands[ 0 ] = t;
        MoveSegOp( ins, new_ins, 0 );
        PrefixIns( ins, new_ins );
        InMemory( NameConflict( ins, t ) );
        break;
    case I2:
    case I4:
    case I8:
    case U8:
        if( ins->operands[ 0 ]->n.class == N_TEMP &&
                ( ins->operands[ 0 ]->v.usage & HAS_MEMORY ) == 0 ) {
            t = AllocTemp( class );
            new_ins = MakeMove( ins->operands[ 0 ], t, class );
            ins->operands[ 0 ] = t;
            MoveSegOp( ins, new_ins, 0 );
            PrefixIns( ins, new_ins );
            InMemory( NameConflict( ins, t ) );
        } else {
            ToMemory( ins, ins->operands[ 0 ] );
        }
        break;
    case U4:
        t = AllocTemp( U8 );
        new_ins = MakeConvert( ins->operands[ 0 ], t, U8, U4 );
        ins->operands[ 0 ] = t;
        MoveSegOp( ins, new_ins, 0 );
        PrefixIns( ins, new_ins );
        InMemory( NameConflict( ins, t ) );
        break;
    default:
        break;
    }
}


static  void    CnvResult( instruction *ins ) {
/**********************************************
    Convert the result of instruction "ins" into a variable of a type
    that can be directly used by an instruction like FSTP or FISTP.
*/

    name                *t;
    instruction         *new_ins;
    type_class_def      class;

    class = ins->type_class;
    switch( class ) {
    case U1:
    case I1:
        t = AllocTemp( I2 );
        t->v.usage |= NEEDS_MEMORY | USE_MEMORY;
        new_ins = MakeConvert( t, ins->result, class, I2 );
        ins->result = t;
        MoveSegRes( ins, new_ins );
        SuffixIns( ins, new_ins );
        break;
    case U2:
        t = AllocTemp( I4 );
        t->v.usage |= NEEDS_MEMORY | USE_MEMORY;
        new_ins = MakeConvert( t, ins->result, class, I4 );
        ins->result = t;
        MoveSegRes( ins, new_ins );
        SuffixIns( ins, new_ins );
        break;
    case I2:
    case I4:
    case I8:
    case U8:
        ToMemory( ins, ins->result );
        break;
    case U4:
        t = AllocTemp( XX );
        t->n.size = 8;
        t->v.usage |= NEEDS_MEMORY | USE_MEMORY;
        new_ins = MakeMove( TempOffset(t,0,U4), ins->result, U4);
        ins->result = t;
        MoveSegRes( ins, new_ins );
        SuffixIns( ins, new_ins );
        break;
    default:
        break;
    }
}


extern  int     Count87Regs( hw_reg_set regs ) {
/***********************************************
    Count the number of 8087 registers named in hw_reg_set "regs".
*/

    int         count;
    int         i;

    i = 0;
    count = 0;
    for(;;) {
        if( HW_Ovlap( FPRegs[ i ], regs ) ) {
            ++count;
        }
        if( i == 7 ) break;
        ++i;
    }
    return( count );
}


extern  bool    FPStackIns( instruction *ins ) {
/**********************************************/

    if( !_FPULevel( FPU_87 ) ) return( FALSE );
    if( _OpIsCall( ins->head.opcode ) ) return( TRUE );
    if( _Is87Ins( ins ) ) return( TRUE );
    return( FALSE );
}


extern  bool    FPSideEffect( instruction *ins ) {
/*************************************************
    Return TRUE if instruction "ins" is an instruction that has a side
    effect, namely pushes or pops the 8087 stack.

*/

    int         i;
    bool        has_fp_reg;

    if( !_FPULevel( FPU_87 ) ) return( FALSE );
    /* calls require a clean stack */
    if( _OpIsCall( ins->head.opcode ) ) return( TRUE );
    if( !_Is87Ins( ins ) ) return( FALSE );
    i = ins->num_operands;
    has_fp_reg = FALSE;
    while( --i >= 0 ) {
        if( ins->operands[ i ]->n.class == N_REGISTER ) {
            if( HW_COvlap( ins->operands[i]->r.reg, HW_FLTS ) ) {
                has_fp_reg = TRUE;
            }
        }
    }
    if( ins->result != NULL ) {
        if( ins->result->n.class == N_REGISTER ) {
            if( HW_COvlap( ins->result->r.reg, HW_FLTS ) ) {
                has_fp_reg = TRUE;
            }
        }
    }
    if( has_fp_reg ) {
        if( ins->ins_flags & INS_PARAMETER ) return( TRUE );
        if( ins->stk_entry != ins->stk_exit ) return( TRUE );
    }
    return( FALSE );
}


static  bool    CanStack( name *name ) {
/***************************************
    Return true if "name" is a candidate for an 8087 "stack" location.
*/

    instruction         *first;
    instruction         *last;
    conflict_node       *conf;

    if( ( name->v.usage & USE_IN_ANOTHER_BLOCK ) ) return( FALSE );
    conf = name->v.conflict;
    while( conf != NULL ) {
        if( conf == NULL ) return( TRUE ); /* if conflict not yet allocated */
        if( conf->start_block == NULL ) return( FALSE );
        if( conf->ins_range.first == NULL ) return( FALSE );
        if( conf->ins_range.last == NULL ) return( FALSE );
        if( conf->ins_range.first == conf->ins_range.last ) return( FALSE );
        first = conf->ins_range.first->head.next;
        last = conf->ins_range.last;
        for( ;; ) {
            if( first == last ) break;
            if( first->head.opcode == OP_CALL ) return( FALSE );
            if( first->head.opcode == OP_CALL_INDIRECT ) return( FALSE );
            first = first->head.next;
        }
        conf = conf->next_for_name;
    }
    return( TRUE );
}


static  void    StackShortLivedTemps( void ) {
/***************************************
    Most temporaries are marked as CAN_STACK when they are back end
    generated temps which are used to hold an intermediate result from
    an expression tree.  Some user or front end temps also fall into the
    CAN_STACK category if they are defined once then used.  This catches
    temps that are defined in one instruction and used in the next one.

*/

    conflict_node       *conf;
    instruction         *ins1;
    instruction         *ins2;
    name                *temp;

    for( conf = ConfList; conf != NULL; conf = conf->next_conflict ) {
        ins1 = conf->ins_range.first;
        ins2 = conf->ins_range.last;
        if( ins1 == NULL ) continue;
        if( ins2 == NULL ) continue;
        if( !_Is87Ins( ins1 ) ) continue;
        if( !_Is87Ins( ins2 ) ) continue;
        if( ins1->ins_flags & INS_PARAMETER ) continue;
        if( ins2->ins_flags & INS_PARAMETER ) continue;
        if( ins1->head.next != ins2 ) continue;
        temp = conf->name;
        if( temp->n.class != N_TEMP ) continue;
        if( temp->t.temp_flags & CROSSES_BLOCKS ) continue;
        if( temp->t.alias != temp ) continue;
        FPSetStack( temp );
    }
}


static  void    CheckForStack( name *temp )
/*************************************
    used by NoStackAcrossCalls
*/
{
    if( temp->n.class != N_TEMP ) return;
    if( CanStack( temp ) ) return;
    temp->t.temp_flags &= ~CAN_STACK;
}


static  void    NoStackAcrossCalls( void ) {
/*************************************
    Since a call requires the stack of the 8087 to be empty, we can't
    hold a value in a stack register across a call instrution.  This
    routine turns off the CAN_STACK attribute in temps which live across
    a call instruction. Also, we cannot stack the operands of POW, ATAN2, etc.
    Run the block list, rather than the temp list for speed when we're
    BlockByBlock.
*/

    block       *blk;
    instruction *ins;
    int         i;

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


extern  type_class_def  FPInsClass( instruction *ins ) {
/*******************************************************
    Return FD if the instruction will use the 8087.
*/

    if( !_FPULevel( FPU_87 ) ) return( XX );
    if( !_Is87Ins( ins ) ) return( XX );
    return( FD );
}


extern  void    FPSetStack( name *name ) {
/*****************************************
    Turn on the CAN_STACK attribute in "name" if its ok to do so.
*/

    if( name->n.class != N_TEMP ) return;
    if( name->v.usage & USE_IN_ANOTHER_BLOCK ) return;
    if( !_IsFloating( name->n.name_class ) ) return;
    name->t.temp_flags |= CAN_STACK;
}


extern  bool    FPIsStack( name *name ) {
/****************************************
    return TRUE if "name" is a stackable temp.
*/

    if( name->n.class != N_TEMP ) return( FALSE );
    if( ( name->t.temp_flags & CAN_STACK ) == EMPTY ) return( FALSE );
    return( TRUE );
}


extern  bool    FPStackOp( name *name ) {
/****************************************
    return TRUE if "name" is a stackable temp.
*/

    if( !_FPULevel( FPU_87 ) ) return( FALSE );
    return( FPIsStack( name ) );
}


extern  void    FPNotStack( name *name ) {
/*****************************************
    Turn off the CAN_STACK attribute of "name".  This is done whenever
    an instruction is moved during an optimization, since it could cause
    the value to be not at top of stack at the reference.
*/

    if( name->n.class == N_TEMP ) {
        name->t.temp_flags &= ~CAN_STACK;
    }
}


extern  bool    FPIsConvert( instruction *ins ) {
/************************************************
    return TRUE if "ins" is a converstion that could be handled by the 8087.
*/

    type_class_def      op_class;
    type_class_def      res_class;

    if( !_FPULevel( FPU_87 ) ) return( FALSE );
    if( ins->operands[ 0 ]->n.class == N_CONSTANT ) return( FALSE );
    op_class = ins->operands[ 0 ]->n.name_class;
    res_class = ins->result->n.name_class;
    if( op_class == res_class ) return( FALSE );
    if( _Is87Ins( ins ) ) return( TRUE );
    return( FALSE );
}

static  void    FSinCos( void ) {
/*************************/

    block       *blk;
    instruction *ins;

    blk = HeadBlock;
    while( blk != NULL ) {
        ins = blk->ins.hd.next;
        while( ins->head.opcode != OP_BLOCK ) {
            if( ins->head.opcode == OP_SIN ) {
                FindSinCos( ins, OP_COS );
            } else if( ins->head.opcode == OP_COS ) {
                FindSinCos( ins, OP_SIN );
            }
            ins = ins->head.next;
        }
        blk = blk->next_block;
    }
}

static  void   FindSinCos( instruction *ins, opcode_defs next_op ) {
/*****************************************************************/

    instruction *next;
    instruction *new_ins;
    name        *temp;

    next = ins->head.next;
    for( ;; ) {
        if( next->head.opcode == OP_BLOCK ) return;
        if( ReDefinedBy( next, ins->operands[ 0 ] ) ) return;
        if( next->head.opcode == next_op ) {
            if( next->operands[ 0 ] == ins->operands[ 0 ] &&
                next->type_class == ins->type_class ) break;
        }
        next = next->head.next;
    }
    temp = AllocTemp( ins->type_class );
    new_ins = MakeUnary( next_op, ins->operands[0], temp, ins->type_class );
    next->head.opcode = OP_MOV;
    next->operands[ 0 ] = temp;
    SuffixIns( ins, new_ins );
    UpdateLive( ins, next );
}

⌨️ 快捷键说明

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