i87exp.c

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

C
1,207
字号
/****************************************************************************
*
*                            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:  Intel 80x87 floating point instruction expansion.
*
****************************************************************************/


#include "standard.h"
#include "coderep.h"
#include "addrname.h"
#include "model.h"
#include "opcodes.h"
#include "conflict.h"
#include "procdef.h"
#include "pattern.h"
#include "vergen.h"
#include "gen8087.h"
#include "zoiks.h"
#include "cfloat.h"
#include "cgaux.h"
#include "funits.h"
#include "feprotos.h"

extern  block           *HeadBlock;
extern  bool            BlockByBlock;
extern  hw_reg_set      FPRegs[];
extern  name            *FPStatWord;
extern  int             Max87Stk;
extern  bool            Used87;
extern  byte            OptForSize;
extern  opcode_entry    DoNop[];
extern  type_length     TypeClassSize[];

extern  void            Opt8087( void );
extern  bool            DoesSomething(instruction*);
extern  int             NumOperands(instruction*);
extern  name            *AllocRegName(hw_reg_set);
extern  int             Count87Regs(hw_reg_set);
extern  instruction     *MakeBinary(opcode_defs,name*,name*,name*,type_class_def);
extern  name            *AllocIntConst(int);
extern  void            PrefixIns(instruction*,instruction*);
extern  instruction     *MakeMove(name*,name*,type_class_def);
extern  name            *AllocIndex(name*,name*,type_length,type_class_def);
extern  void            ReplIns(instruction*,instruction*);
extern  instruction     *MakeUnary(opcode_defs,name*,name*,type_class_def);
extern  void            SuffixIns(instruction*,instruction*);
extern  void            DoNothing(instruction*);
extern  name            *AllocTemp(type_class_def);
extern  void            AllocALocal(name*);
extern  void            RevCond(instruction*);
extern  void            MoveSegRes(instruction*,instruction*);
extern  void            MoveSegOp(instruction*,instruction*,int);
extern  hw_reg_set      *IdxRegs( void );
extern  void            FPCalcMax( void );
extern  void            InitFPStkReq( void );

/* forward declarations */
static  void            ExpCompare( instruction *ins,
                                    operand_type op1, operand_type op2 );
static  void            ExpBinary( instruction *ins,
                                   operand_type op1, operand_type op2 );
static  void            ExpBinFunc( instruction *ins,
                                    operand_type op1, operand_type op2 );
extern  int             FPRegNum( name *reg_name );
static  void            RevOtherCond( block *blk, instruction *ins );


//NYI: probably need more opcode entries for more resolution with func. units
static  opcode_entry    FNOP    = { SETS_CC,  0, G_NO, 0, FU_FOP };


static opcode_entry    RRFBIN[]  = {
                                  { PRESERVE, 0, G_RRFBIN, 0, FU_FADD },
                                  { PRESERVE, 0, G_RRFBIN, 0, FU_FMUL },
                                  { PRESERVE, 0, G_RRFBIN, 0, FU_FDIV },
};
static opcode_entry    RNFBIN[]  = {
                                  { PRESERVE, 0, G_RNFBIN, 0, FU_FADD },
                                  { PRESERVE, 0, G_RNFBIN, 0, FU_FMUL },
                                  { PRESERVE, 0, G_RNFBIN, 0, FU_FDIV },
};
static opcode_entry    RRFBINP[] = {
                                  { PRESERVE, 0, G_RRFBINP, 0, FU_FADD },
                                  { PRESERVE, 0, G_RRFBINP, 0, FU_FMUL },
                                  { PRESERVE, 0, G_RRFBINP, 0, FU_FDIV },
};
static opcode_entry    RNFBINP[] = {
                                  { PRESERVE, 0, G_RNFBINP, 0, FU_FADD },
                                  { PRESERVE, 0, G_RNFBINP, 0, FU_FMUL },
                                  { PRESERVE, 0, G_RNFBINP, 0, FU_FDIV },
};
static opcode_entry    RRFBIND[] = {
                                  { PRESERVE, 0, G_RRFBIND, 0, FU_FADD },
                                  { PRESERVE, 0, G_RRFBIND, 0, FU_FMUL },
                                  { PRESERVE, 0, G_RRFBIND, 0, FU_FDIV },
};
static opcode_entry    RNFBIND[] = {
                                  { PRESERVE, 0, G_RNFBIND, 0, FU_FADD },
                                  { PRESERVE, 0, G_RNFBIND, 0, FU_FMUL },
                                  { PRESERVE, 0, G_RNFBIND, 0, FU_FDIV },
};
static opcode_entry    MRFBIN[]  = {
                                  { PRESERVE, 0, G_MRFBIN, 0, FU_FADD },
                                  { PRESERVE, 0, G_MRFBIN, 0, FU_FMUL },
                                  { PRESERVE, 0, G_MRFBIN, 0, FU_FDIV },
};
static opcode_entry    MNFBIN[]  = {
                                  { PRESERVE, 0, G_MNFBIN, 0, FU_FADD },
                                  { PRESERVE, 0, G_MNFBIN, 0, FU_FMUL },
                                  { PRESERVE, 0, G_MNFBIN, 0, FU_FDIV },
};

static  opcode_entry    MFLD    = { PRESERVE, 0, G_MFLD, 0, FU_FOP };
static  opcode_entry    RFLD    = { PRESERVE, 0, G_RFLD, 0, FU_FOP };
static  opcode_entry    MFST    = { PRESERVE, 0, G_MFST, 0, FU_FOP };
#if _TARGET & _TARG_80386
static  opcode_entry    MFSTRND = { PRESERVE, 0, G_MFSTRND, 0, FU_FOP };
#endif
static  opcode_entry    MFST2   = { PRESERVE, 0, G_MFST, 0, FU_FOP };
static  opcode_entry    RFST    = { PRESERVE, 0, G_RFST, 0, FU_FOP };
static  opcode_entry    FCHS    = { PRESERVE, 0, G_FCHS, 0, FU_FOP };
static  opcode_entry    FMATH   = { PRESERVE, 0, G_FMATH, 0, FU_TRIG };
static  opcode_entry    IFUNC   = { NO_CC,    0, G_IFUNC, 0, FU_TRIG };
static  opcode_entry    FCHOP   = { PRESERVE, 0, G_FCHOP, 0, FU_FOP };
static  opcode_entry    FLDZ    = { PRESERVE, 0, G_FLDZ, 0, FU_FOP };
static  opcode_entry    FLD1    = { PRESERVE, 0, G_FLD1, 0, FU_FOP };
static  opcode_entry    FCOMPP  = { SETS_CC,  0, G_FCOMPP, 0, FU_FOP };
static  opcode_entry    MCOMP   = { SETS_CC,  0, G_MCOMP, 0, FU_FOP };
static  opcode_entry    RCOMP   = { SETS_CC,  0, G_RCOMP, 0, FU_FOP };
static  opcode_entry    MFSTNP  = { PRESERVE, 0, G_MFSTNP, 0, FU_FOP };
static  opcode_entry    RFSTNP  = { PRESERVE, 0, G_RFSTNP, 0, FU_FOP };
static  opcode_entry    FWAIT   = { PRESERVE, 0, G_FWAIT, 0, FU_FOP };//NYI:??
static  opcode_entry    FXCH    = { PRESERVE, 0, G_FXCH, 0, FU_FOP };
static  opcode_entry    RC      = { PRESERVE, 0, G_RC, 0, FU_FOP };
#if _TARGET & _TARG_IAPX86
static  opcode_entry    RR1     = { PRESERVE, 0, G_RR1, 0, FU_FOP };
static  opcode_entry    WORDR1  = { PRESERVE, 0, G_WORDR1, 0, FU_FOP };
#endif

static  name    *ST0;
static  name    *ST1;

static  opcode_entry *GenTab( instruction *ins, opcode_entry *array ) {
/*********************************************************************/

    switch( ins->head.opcode ) {
    case OP_DIV:
        return( array + 2 );
    case OP_MUL:
        return( array + 1 );
    default:
        return( array );
    }
}


extern  bool    FPStackReg( name *reg_name ) {
/********************************************/

    int         reg_num;

    reg_num = FPRegNum( reg_name );
    if( reg_num == -1 ) return( FALSE );
    if( reg_num < Max87Stk ) return( TRUE );
    return( FALSE );
}


extern  int     FPRegNum( name *reg_name ) {
/*******************************************
    given a name, return the 8087 register number (0-7) or -1 if
    it isn't an 8087 register
*/

    hw_reg_set  tmp;

    if( reg_name == NULL ) return( -1 );
    if( reg_name->n.class != N_REGISTER ) return( -1 );
    tmp = reg_name->r.reg;
    HW_COnlyOn( tmp, HW_FLTS );
    if( HW_CEqual( tmp, HW_ST0 ) ) return( 0 );
    if( HW_CEqual( tmp, HW_ST1 ) ) return( 1 );
    if( HW_CEqual( tmp, HW_ST2 ) ) return( 2 );
    if( HW_CEqual( tmp, HW_ST3 ) ) return( 3 );
    if( HW_CEqual( tmp, HW_ST4 ) ) return( 4 );
    if( HW_CEqual( tmp, HW_ST5 ) ) return( 5 );
    if( HW_CEqual( tmp, HW_ST6 ) ) return( 6 );
    if( HW_CEqual( tmp, HW_ST7 ) ) return( 7 );
    return( -1 );
}

extern  name    *ST( int num ) {
/*******************************
    return an N_REGISTER for ST(num)
*/

    return( AllocRegName( FPRegs[  num  ] ) );
}

extern  instruction     *PrefFLDOp( instruction *ins,
                                    operand_types op, name *opnd ) {
/*****************************************************************/

    instruction *new_ins = NULL;

    switch( op ) {
    case OP_STK0:
    case OP_STKI:
        new_ins = MakeUnary( OP_MOV, opnd, ST0, FD );
        new_ins->u.gen_table = &RFLD;
        break;
    case OP_MEM:
        new_ins = MakeUnary( OP_MOV, opnd, ST0, FD );
        new_ins->u.gen_table = &MFLD;
        MoveSegOp( ins, new_ins, 0 );
        break;
    case OP_CONS:
        new_ins = MakeUnary( OP_MOV, opnd, ST0, FD );
        if( CFTest( opnd->c.value ) ) {
            new_ins->u.gen_table = &FLD1;
        } else {
            new_ins->u.gen_table = &FLDZ;
        }
        break;
    }
    PrefixIns( ins, new_ins );
    return( new_ins );
}


static  void    PrefixFLDOp( instruction *ins, operand_types op, int i ) {
/*************************************************************************
    Prefix the floating point instruction "ins" with an FLD instruction
    for one of its operands (ins->operands[i]).  That operand has
    classification "op".
*/

    name        *opnd;
    instruction *new_ins;

    opnd = ins->operands[ i ];
    ins->operands[ i ] = ST0;
    new_ins = PrefFLDOp( ins, op, opnd );
    new_ins->stk_exit = new_ins->stk_entry + 1;
    ins->stk_entry++;
    ins->operands[ i ] = ST0;
}


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

    return( ins->u.gen_table == &MFST2 );
}


extern  instruction     *SuffFSTPRes( instruction *ins,
                                      name *opnd, result_type res ) {
/*******************************************************************/

    instruction *new_ins;

    new_ins = MakeUnary( OP_MOV, ST0, opnd, FD );
    if( res == RES_STKI ) {
        new_ins->u.gen_table = &RFST;
    } else if( res == RES_MEM_THROWAWAY ) {
        new_ins->u.gen_table = &MFST2; // so we can turn it into fstp st(0) later
    } else {
        new_ins->u.gen_table = &MFST;
    }
    if( ins->head.opcode != OP_BLOCK ) {
        MoveSegRes( ins, new_ins );
    }
    SuffixIns( ins, new_ins );
    return( new_ins );
}


static  instruction     *SuffixFSTPRes( instruction *ins ) {
/***********************************************************
    Suffix the floating point instruction "ins" with an FSTP instruction
    for its result (ins->result).
*/

    instruction *new_ins;
    name        *opnd;

    opnd = ins->result;
    ins->result = ST0;
    new_ins = SuffFSTPRes( ins, opnd, RES_MEM );
    new_ins->stk_entry = ins->stk_exit + 1;
    ins->stk_exit++;
    return( new_ins );
}

extern  instruction     *SuffFXCH( instruction *ins, int i ) {
/************************************************************/

    instruction *new_ins;

    new_ins = MakeUnary( OP_MOV, ST0, ST(i), FD );
    new_ins->u.gen_table = &FXCH;
    SuffixIns( ins, new_ins );
    new_ins->stk_exit = new_ins->stk_entry;
    return( new_ins );
}

extern  instruction     *PrefFXCH( instruction *ins, int i ) {
/*************************************************************
    Prefix an instruction "ins" with an FXCH ST(i)
*/

    instruction *new_ins;

    new_ins = MakeUnary( OP_MOV, ST0, ST(i), FD );
    new_ins->u.gen_table = &FXCH;
    PrefixIns( ins, new_ins );
    new_ins->stk_exit = new_ins->stk_entry;
    return( new_ins );
}


static  void    PrefixChop( instruction *ins ) {
/***********************************************
    Prefix an instruction "ins" with an instruction that will truncate
    ST(0) to the nearest integer.
*/

    instruction *new_ins;

    if( ins->head.opcode == OP_ROUND ) return;
    if( _IsFloating( ins->result->n.name_class ) ) return;
    new_ins = MakeUnary( OP_MOV, ST0, ST0, FD );
    new_ins->u.gen_table = &FCHOP;
    PrefixIns( ins, new_ins );
    new_ins->stk_exit = ins->stk_entry;
}

#if _TARGET & _TARG_80386
static    int     WantsChop( instruction *ins ) {
/************************************************
    Check whether instruction "ins" needs an instruction that will truncate
    ST(0) to the nearest integer.
*/
    if( ins->head.opcode == OP_ROUND )
        return( FALSE );
    if( _IsFloating( ins->result->n.name_class ) )
        return( FALSE );
    return( TRUE );
}
#endif

static  instruction     *ExpUnary( instruction *ins,
                                    operand_type src, result_type res,
                                    opcode_entry *table ) {
/************************************************************************
    Expand a unary instruction "ins" using classifications "src" and "res"
*/

    instruction *unary;

    ins->u.gen_table = table;
    unary = ins;
    if( src != OP_STK0 ) {
        PrefixFLDOp( ins, src, 0 );
    }
    if( res != RES_STK0 ) {
        ins = SuffixFSTPRes( ins );
    }
    unary->operands[ 0 ] = ST0;
    unary->result = ST0;
    return( ins );
}


static  instruction     *ExpCall( instruction *ins ) {
/*****************************************************
    Expand a call instruction.  Its not really an 8087 instruction but
    we must take into account how many parameters it pops off the 8087

⌨️ 快捷键说明

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