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 + -
显示快捷键?