i87opt.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 906 行 · 第 1/3 页
C
906 行
next = _BLOCK( next )->next_block->ins.hd.next;
}
}
return( FALSE );
}
static void UseInOther( name *op )
{
if( op == NULL ) return;
switch( op->n.class ) {
case N_TEMP:
case N_MEMORY:
op->v.usage |= USE_IN_ANOTHER_BLOCK;
break;
case N_INDEXED:
UseInOther( op->i.index );
UseInOther( op->i.base );
break;
default:
break;
}
}
static int FPPushDelay( pn parm, call_state *state ) {
/**********************************************************
For each parm, move it into a temp, and "push" the temp onto the
8087 stack just before the call instruction. If the calculation of
the parm can be moved down just in front of the call, we do that,
instead of using a temporary.
*/
instruction *ins;
instruction *new_ins;
an addr;
pn next_parm;
int parms;
parms = 0;
for( ; parm != NULL; parm = next_parm ) {
next_parm = parm->next;
if( parm->ins != NULL ) continue;
addr = parm->name;
if( addr->tipe->attr & TYPE_FLOAT && HW_COvlap( parm->regs,HW_FLTS ) ){
++parms;
if( addr->format != NF_INS ) {
_Zoiks( ZOIKS_043 );
}
ins = addr->u.ins;
if( PushDelayedIfStackOperand( ins, parm, state ) ) continue;
if( PushDelayedIfRedefinition( ins, parm, state ) ) continue;
/* we can push it just before the CALL */
if( addr->flags & ADDR_CROSSED_BLOCKS ) {
UseInOther( ins->operands[0] );
if( ins->num_operands > 1 ) UseInOther( ins->operands[1] );
}
new_ins = MakeNary( ins->head.opcode, ins->operands[ 0 ],
ins->operands[ 1 ], AllocRegName( HW_ST0 ),
ins->type_class, ins->base_type_class,
ins->num_operands );
Pushes( new_ins );
new_ins->num_operands = ins->num_operands;
AddIns( new_ins );
#if _TARGET & _TARG_80386
if( state->attr & ROUTINE_STACK_RESERVE ) {
ReserveStack( state, new_ins, addr->tipe->length );
}
#endif
BGDone( addr ); /* so ins DOES get freed*/
parm->ins = new_ins;
}
}
return( parms );
}
extern void FPPushParms( pn parm, call_state *state ) {
/**********************************************************
"push" parameters onto the 8087 stack. If parameters can be pushed
as soon as they are calculated, do that (FPPushImmed), otherwise we
have to "push" it onto the 8087 just before the call instruction
(FPPushDelay). For each parameter there is an address_node (an) of
type NF_INS, which not had the result field filled in yet.
*/
int parms;
if( _FPULevel( FPU_87 ) ) {
parms = 0;
if( CanPushImmed( parm, &parms ) &&
parms < Max87Stk &&
( state->attr & ROUTINE_STACK_RESERVE ) == 0 ) {
parms = FPPushImmed( parm );
} else {
if( parms != 0 ) {
parms = FPPushDelay( parm, state );
}
}
HW_CTurnOff( state->parm.used, HW_FLTS );
while( --parms >= 0 ) {
HW_TurnOn( state->parm.used, FPRegs[ parms ] );
}
}
}
extern void FPOptimize( void ) {
/*****************************
Fix up the 8087 instructions. The instructions so far
*/
if( _FPULevel( FPU_87 ) ) {
if( _IsntModel( NO_OPTIMIZATION ) ) {
Opt8087();
}
Wait8087();
}
}
#define G(x) (x)->u.gen_table->generate
static opcode_entry FSINCOS = { PRESERVE, 0, G_FSINCOS, 0, FU_TRIG };
#define _OTHER( x ) ( (x) == OP_SIN ? OP_COS : OP_SIN )
static bool FSinCos( instruction *ins1 ) {
/********************************************
find the FSINCOS sequence
*/
instruction *ins2;
instruction *ins3;
instruction *ins4;
if( !_IsTargetModel( I_MATH_INLINE ) ) {
return( FALSE );
}
ins2 = ins1->head.next;
ins3 = ins2->head.next;
ins4 = ins3->head.next;
if( G( ins1 ) == G_MFLD ) {
if( ins2->head.opcode != OP_SIN && ins2->head.opcode != OP_COS ) {
return( FALSE );
}
if( G( ins3 ) != G_MFLD ) {
return( FALSE );
}
if( ins1->operands[ 0 ] != ins3->operands[ 0 ] ) {
return( FALSE );
}
if( ins4->head.opcode != _OTHER( ins2->head.opcode ) ) {
return( FALSE );
}
} else if( G( ins1 ) == G_RFLD ) {
if( ins2->head.opcode != OP_SIN && ins2->head.opcode != OP_COS ) {
return( FALSE );
}
if( G( ins3 ) != G_RFLD ) {
return( FALSE );
}
if( FPRegNum( ins1->operands[ 0 ] ) !=
FPRegNum( ins3->operands[ 0 ] ) - 1 ) {
return( FALSE );
}
if( ins4->head.opcode != _OTHER( ins2->head.opcode ) ) {
return( FALSE );
}
} else if( ins1->head.opcode == OP_SIN ) {
if( G( ins2 ) != G_RFLD ) {
return( FALSE );
}
if( FPRegNum( ins2->operands[ 0 ] ) != 1 ) {
return( FALSE );
}
if( ins3->head.opcode != _OTHER( ins1->head.opcode ) ) {
return( FALSE );
}
ins4 = ins3;
ins3 = ins2;
ins2 = ins1;
} else {
return( FALSE );
}
ins2->u.gen_table = &FSINCOS;
if( ins2->head.opcode != OP_SIN ) {
PrefFXCH( ins3, 1 );
}
FreeIns( ins3 );
FreeIns( ins4 );
return( TRUE );
}
static instruction *Next87Ins( instruction *ins ) {
/******************************************************/
instruction *next;
next = ins->head.next;
for( ;; ) {
if( next->head.opcode == OP_BLOCK ) return( ins );
if( DoesSomething( next ) ) break;
next = next->head.next;
}
return( next );
}
static bool RedundantStore( instruction *ins ) {
/***************************************************
*/
instruction *next;
for( next = ins->head.next;
next->head.opcode != OP_BLOCK; next = next->head.next ) {
if( next->result == ins->result ) {
if( G( next ) == G_MFSTNP || G( next ) == G_MFST ) {
return( TRUE );
}
}
if( InsOrderDependant( ins, next ) ) return( FALSE );
}
return( FALSE );
}
static void AdjustST( name **p, int adjust )
/**********************************************/
{
*p = ST( FPRegNum( *p ) + adjust );
}
static instruction *BackUpAndFree( instruction *ins, instruction *junk1,
instruction *junk2 ) {
/*************************************************************
*/
instruction *ret;
ret = ins->head.prev;
if( junk1 != NULL ) FreeIns( junk1 );
if( junk2 != NULL ) FreeIns( junk2 );
if( ret->head.opcode == OP_BLOCK ) ret = ret->head.next;
return( ret );
}
#if _TARGET & _TARG_IAPX86
#define RL_MOVE_REG RL_WORD
#else
#define RL_MOVE_REG RL_DOUBLE
#endif
static instruction *To86Move( instruction *ins, instruction *next ) {
/************************************************************************
Turn a move which uses the 8087 (FLD X, FSTP Y) into a move using
the 8086 using an available 8086 register.
*/
hw_reg_set *regs;
name *reg;
instruction *ret;
ret = ins->head.next;
for( regs = RegSets[ RL_MOVE_REG ]; ; ++regs ) {
if( HW_CEqual( *regs, HW_EMPTY ) ) return( ret );
if( HW_Ovlap( *regs, next->head.live.regs ) ) continue;
if( HW_Ovlap( *regs, ins->head.live.regs ) ) continue;
reg = AllocRegName( *regs );
break;
}
if( next->result->n.name_class == FS ) {
#if _TARGET & _TARG_80386
MoveThrough( ins->operands[ 0 ], next->result, ins, next, reg, U4 );
#else
if( OptForSize > 50 ) return( ret );
MoveThrough( LowPart( ins->operands[ 0 ], U2 ),
LowPart( next->result, U2 ), ins, next, reg, U2 );
MoveThrough( HighPart( ins->operands[ 0 ], U2 ),
HighPart( next->result, U2 ), ins, next, reg, U2 );
#endif
} else {
if( OptForSize > 50 ) return( ret );
#if _TARGET & _TARG_80386
MoveThrough( LowPart( ins->operands[ 0 ], U4 ),
LowPart( next->result, U4 ), ins, next, reg, U4 );
MoveThrough( HighPart( ins->operands[ 0 ], U4 ),
HighPart( next->result, U4 ), ins, next, reg, U4 );
#else
MoveThrough( LowPart( LowPart( ins->operands[ 0 ], U4 ), U2 ),
LowPart( LowPart( next->result , U4 ), U2 ),
ins, next, reg, U2 );
MoveThrough( HighPart( LowPart( ins->operands[ 0 ], U4 ), U2 ),
HighPart( LowPart( next->result , U4 ), U2 ),
ins, next, reg, U2 );
MoveThrough( LowPart( HighPart( ins->operands[ 0 ], U4 ), U2 ),
LowPart( HighPart( next->result , U4 ), U2 ),
ins, next, reg, U2 );
MoveThrough( HighPart( HighPart( ins->operands[ 0 ], U4 ), U2 ),
HighPart( HighPart( next->result , U4 ), U2 ),
ins, next, reg, U2 );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?