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