i87reg.c

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

C
817
字号
/****************************************************************************
*
*                            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:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include "standard.h"
#include "coderep.h"
#include "model.h"
#include "opcodes.h"
#include "procdef.h"
#include "conflict.h"
#include "typedef.h"
#include "gen8087.h"
#include "zoiks.h"

extern  block           *HeadBlock;
extern  proc_def        *CurrProc;
extern  hw_reg_set      FPRegs[];
extern  name            *Names[];
extern  name            *FPStatWord;
extern  int             Max87Stk;
extern  conflict_node   *ConfList;

extern  void            SuffixIns(instruction*,instruction*);
extern  name            *AllocIntConst(int);
extern  instruction     *MakeMove(name*,name*,type_class_def);
extern  name            *TempOffset(name*,type_length,type_class_def);
extern  conflict_node   *InMemory(conflict_node*);
extern  conflict_node   *NameConflict(instruction*,name*);
extern  void            PrefixIns(instruction*,instruction*);
extern  void            MoveSegOp(instruction*,instruction*,int);
extern  void            MoveSegRes(instruction*,instruction*);
extern  instruction     *MakeConvert(name*,name*,type_class_def,type_class_def);
extern  name            *AllocTemp(type_class_def);
extern  bool            AssignARegister(conflict_node*,hw_reg_set);
extern  conflict_node   *FindConflictNode(name*,block*,instruction*);
extern  void            LiveInfoUpdate(void);
extern  int             NumOperands(instruction *);
extern  bool            ReDefinedBy(instruction*,name*);
extern  instruction     *MakeUnary(opcode_defs,name*,name*,type_class_def);
extern  void            UpdateLive(instruction*,instruction*);
extern  bool            DoesSomething(instruction*);

/* forward declarations */
static  void            CnvOperand( instruction *ins );
static  void            FPAlloc( void );
static  void            NoStackAcrossCalls( void );
static  void            StackShortLivedTemps( void );
static  void            FSinCos( void );
static  void            CnvResult( instruction *ins );
static  void            FindSinCos( instruction *ins, opcode_defs next_op );
extern  int             Count87Regs( hw_reg_set regs );
static  void            FPConvert( void );
extern  void            FPSetStack( name *name );

extern  void    FPRegAlloc( void ) {
/*****************************
    Allocate registers comprising the "stack" portion of the 8087.
*/

    if( _FPULevel( FPU_87 ) ) {
        if( _FPULevel( FPU_387 ) ) {
            FSinCos();
        }
        StackShortLivedTemps();
        NoStackAcrossCalls();
        FPAlloc();
    }
}




static byte StackReq8087[LAST_IFUNC-FIRST_IFUNC+1] = {
/********************************************************
    how much stack over and above the parm
    does the operation require? NB: this number + number parms must be <= 4
*/
        2,        /* OP_POW */
        2,        /* OP_P5DIV */
        0,        /* OP_ATAN2 */
        0,        /* OP_FMOD */
        0,        /* OP_NEGATE */
        0,        /* OP_COMPLEMENT */
        1,        /* OP_LOG */
        3,        /* OP_COS */
        3,        /* OP_SIN */
        2,        /* OP_TAN */
        0,        /* OP_SQRT */
        0,        /* OP_FABS */
        2,        /* OP_ACOS */
        2,        /* OP_ASIN */
        1,        /* OP_ATAN */
        2,        /* OP_COSH */
        2,        /* OP_EXP */
        1,        /* OP_LOG10 */
        2,        /* OP_SINH */
        2         /* OP_TANH */
};

static byte StackReq387[LAST_IFUNC-FIRST_IFUNC+1] = {
/********************************************************
    how much stack over and above the parm
    does the operation require? NB: this number + number parms must be <= 4
*/
        2,        /* OP_POW */
        0,        /* OP_ATAN2 */
        0,        /* OP_FMOD */
        0,        /* OP_NEGATE */
        0,        /* OP_COMPLEMENT */
        1,        /* OP_LOG */
        1,        /* OP_COS */
        1,        /* OP_SIN */
        1,        /* OP_TAN */
        0,        /* OP_SQRT */
        0,        /* OP_FABS */
        2,        /* OP_ACOS */
        2,        /* OP_ASIN */
        1,        /* OP_ATAN */
        2,        /* OP_COSH */
        2,        /* OP_EXP */
        1,        /* OP_LOG10 */
        2,        /* OP_SINH */
        2         /* OP_TANH */
};

extern  void    InitFPStkReq( void ) {
/******************************/

    if( _IsTargetModel( I_MATH_INLINE ) ) {
        StackReq387[ OP_SIN-FIRST_IFUNC ] = 0;
        StackReq387[ OP_COS-FIRST_IFUNC ] = 0;
    }
}


extern  int     FPStkReq( instruction *ins ) {
/********************************************/

    if( !_OpIsIFunc( ins->head.opcode ) ) return( 0 );
    if( _FPULevel( FPU_387 ) ) {
        return( StackReq387[ ins->head.opcode - FIRST_IFUNC ] );
    } else {
        return( StackReq8087[ ins->head.opcode - FIRST_IFUNC ] );
    }
}


static  bool    MathOpsBlowStack( conflict_node *conf, int stk_level ) {
/*****************************************************************
    See if putting "conf" on the stack would blow the 8087 stack in the
    face of stack requirements for any complicated math operations in
    between.
*/

    instruction *ins;

    ins = conf->ins_range.first;
    if( ins == conf->ins_range.last ) return( TRUE );
    for( ;; ) {
        ins = ins->head.next;
        if( ins == conf->ins_range.last ) break;
        if( FPStkReq( ins ) + stk_level + NumOperands( ins ) >= Max87Stk ) {
            return( TRUE );
        }
    }
    return( FALSE );
}


static  bool    AssignFPResult( block *blk, instruction *ins, int *stk_level ) {
/*******************************************************************************
    Try to assign a "stack" register to the result of instruction
    "ins"., updating "*stk_level" if we did.  These register given out
    will be one of ST(1) ..  ST(Max87Stk) as described in FPAlloc.
    Notice that the result must be a temporary with the "CAN_STACK"
    attribute.  This corresponds to a temporary that is defined once
    then used in a fashion compatible with a stack.  The CAN_STACK
    attribute is determined in TREE.C, and also in StackShortLivedTemps.

*/

    name                *op;
    conflict_node       *conf;
    bool                need_live_update;

    op = ins->result;
    if( op == NULL ) return( FALSE );
    if( op->n.class == N_REGISTER ) {
        if( HW_COvlap( op->r.reg, HW_FLTS ) ) ++*stk_level;
        return( FALSE );
    }
    if( op->n.class != N_TEMP ) return( FALSE );
    if( ( op->t.temp_flags & CAN_STACK ) == 0 ) return( FALSE );
    if( op->v.usage & (USE_ADDRESS | USE_IN_ANOTHER_BLOCK) ) return( FALSE );
    if( !_IsFloating( op->n.name_class ) ) return( FALSE );
    if( *stk_level < 0 ) return( FALSE );
    if( *stk_level >= (Max87Stk-1) ) return( FALSE );
    conf = FindConflictNode( op, blk, ins );
    if( conf == NULL ) return( FALSE );
    if( MathOpsBlowStack( conf, *stk_level ) ) return( FALSE );
    ++*stk_level;
    need_live_update = AssignARegister( conf, FPRegs[ *stk_level ] );
    return( need_live_update );
}


static  void    AssignFPOps( instruction *ins, int *stk_level ) {
/****************************************************************
    This checks for operands which are "stack" registers and for each
    one that is used, it bumps down "*stk_level" since we know that the
    use of the operand will "pop" the 8087 stack.
*/

    int                 old_level;
    name                *op;
    int                 i;

    /* Now check operands ... bump down stack level for each*/
    /* top of stack operand that will be popped (may be more than one)*/
    i = ins->num_operands;
    if( _OpIsCall( ins->head.opcode ) ) {
        *stk_level -= Count87Regs( ins->operands[ CALL_OP_USED ]->r.reg );
    } else {
        old_level = *stk_level;
        while( --i >= 0 ) {
            op = ins->operands[ i ];
            if( op->n.class == N_REGISTER && ( HW_COvlap( op->r.reg, HW_FLTS ) ) ) {
                 --*stk_level;
            }
        }
        if( ins->num_operands < 2 ) return;
        if( ins->operands[ 0 ] != ins->operands[ 1 ] ) return;
        if( old_level == *stk_level ) return;
        ++*stk_level;
    }
}


static  void    SetStackLevel( instruction *ins, int *stk_level ) {
/******************************************************************
    Returns TRUE if a call ignores a return value in ST(0)
*/


    if( !_OpIsCall( ins->head.opcode ) ) return;
    if( !HW_CEqual( ins->result->r.reg, HW_ST0 ) ) return;
    if( !( ins->flags.call_flags & CALL_IGNORES_RETURN ) ) return;
    --*stk_level;
}


static  void    FPAlloc( void ) {
/**************************
   Pre allocate 8087 registers to temporarys that lend themselves
   to a stack architecture.  ST(0) is reserved as the floating top
   of stack pointer.  Notice that by not "assigning" ST(0), we
   give FPExpand one register on the 8087 stack to play with if it
   needs to FLD a memory location or a constant or something.  We
   also set stk_entry, stk_exit to indicate the affect that each
   instruction has on the 8087 stack.  stk_extra indicates how much
   stack over and above stk_entry gets used.


*/
    block               *blk;
    instruction         *ins;
    int                 stk_level;
    int                 sequence;
    bool                need_live_update;
    name                *name;
    instruction         *new_ins;

    HW_CTurnOn( CurrProc->state.unalterable, HW_FLTS );
    FPStatWord = NULL;
    stk_level = 0;
    need_live_update = FALSE;
    for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) {
        ins = blk->ins.hd.next;
        if( ins->head.opcode == OP_BLOCK ) continue;
        ins->stk_entry = stk_level;
        SetStackLevel( ins, &stk_level );
        sequence = 0;
        for( ;; ) {
            /*
             * if we have an ins which looks like "cnv FS FD t1 -> t1" we need to
             * split it up so that we can give it a register, since rDOCVT is so lame
             */
            for( ;; ) { // not really a loop - forgive me
                if( ins->head.opcode != OP_CONVERT ) break;
                if( !( ( ins->type_class == FS && ins->base_type_class == FD ) ||
                      ( ins->type_class == FD && ins->base_type_class == FS ) ) ) break;
                if( ins->operands[0]->n.class == N_REGISTER ) break;
                if( ins->operands[0]->n.class == N_TEMP && ( ( ins->operands[0]->t.temp_flags & CAN_STACK ) != EMPTY ) ) break;
                name = AllocTemp( ins->base_type_class );
                name->t.temp_flags |= CAN_STACK;
                new_ins = MakeMove( ins->operands[ 0 ], name, ins->base_type_class );
                ins->operands[ 0 ] = name;
                MoveSegOp( ins, new_ins, 0 );
                PrefixIns( ins, new_ins );
                ins = new_ins;
                break;
            }
            /* check the result ... if it's top of stack, bump up stack level*/
            if( AssignFPResult( blk, ins, &stk_level ) ) {
                need_live_update = TRUE;
            }
            ins->sequence = sequence;
            ins->stk_exit = stk_level;
            // ins->s.stk_extra = FPStkReq( ins ); // BBB - Mar 22, 1994
            if(  _FPULevel( FPU_586 ) &&
                stk_level == 0 ) ++sequence; // NYI - overflow?
            ins = ins->head.next;
            if( ins->head.opcode == OP_BLOCK ) break;
            ins->stk_entry = stk_level;
            SetStackLevel( ins, &stk_level );
            AssignFPOps( ins, &stk_level );
        }
        if( ( blk->class & RETURN ) && stk_level == 1 ) {
            stk_level = 0;
        }
        if( stk_level != 0 ) {
            _Zoiks( ZOIKS_074 );
        }
    }
    if( need_live_update ) {
        LiveInfoUpdate();
    }
    FPConvert();
}


static  void    FPConvert( void ) {
/****************************
    Make sure all operands of _IsFloating() instructions are a type that
    may be used in an FLD or FST instruction.

*/


    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( ins->head.opcode == OP_CONVERT ) {
                if( _Is87Ins( ins ) ) {
                    CnvOperand( ins );
                    CnvResult( ins );
                }
            }
            ins = next;
        }
        blk = blk->next_block;
    }
}


static  void    ToMemory( instruction *ins, name *t ) {
/******************************************************
    Force "t" into memory (no register may be allocated for it) since we
    can't use 8086 registers in 8087 instructions.
*/

    conflict_node       *conf;

    if( t->n.class == N_TEMP || t->n.class == N_MEMORY ) {
        conf = NameConflict( ins, t );
        if( conf != NULL ) {
            InMemory( conf );
        } else {
            t->v.usage |= NEEDS_MEMORY | USE_MEMORY;
        }
    }
}


static  void    CnvOperand( instruction *ins ) {

⌨️ 快捷键说明

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