i87reg.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 817 行 · 第 1/2 页
C
817 行
/***********************************************
Turn op1 (operands[0]) of instruction "ins" into a variable of a
type that can be used directly by an 8087 instruction like FLD or
FILD.
*/
name *t;
instruction *new_ins;
type_class_def class;
class = ins->base_type_class;
switch( class ) {
case U1:
case I1:
t = AllocTemp( I2 );
new_ins = MakeConvert( ins->operands[ 0 ], t, I2, class );
ins->base_type_class = I2;
ins->operands[ 0 ] = t;
MoveSegOp( ins, new_ins, 0 );
PrefixIns( ins, new_ins );
InMemory( NameConflict( ins, t ) );
break;
case U2:
t = AllocTemp( I4 );
new_ins = MakeConvert( ins->operands[ 0 ], t, I4, class );
ins->base_type_class = I4;
ins->operands[ 0 ] = t;
MoveSegOp( ins, new_ins, 0 );
PrefixIns( ins, new_ins );
InMemory( NameConflict( ins, t ) );
break;
case I2:
case I4:
case I8:
case U8:
if( ins->operands[ 0 ]->n.class == N_TEMP &&
( ins->operands[ 0 ]->v.usage & HAS_MEMORY ) == 0 ) {
t = AllocTemp( class );
new_ins = MakeMove( ins->operands[ 0 ], t, class );
ins->operands[ 0 ] = t;
MoveSegOp( ins, new_ins, 0 );
PrefixIns( ins, new_ins );
InMemory( NameConflict( ins, t ) );
} else {
ToMemory( ins, ins->operands[ 0 ] );
}
break;
case U4:
t = AllocTemp( U8 );
new_ins = MakeConvert( ins->operands[ 0 ], t, U8, U4 );
ins->operands[ 0 ] = t;
MoveSegOp( ins, new_ins, 0 );
PrefixIns( ins, new_ins );
InMemory( NameConflict( ins, t ) );
break;
default:
break;
}
}
static void CnvResult( instruction *ins ) {
/**********************************************
Convert the result of instruction "ins" into a variable of a type
that can be directly used by an instruction like FSTP or FISTP.
*/
name *t;
instruction *new_ins;
type_class_def class;
class = ins->type_class;
switch( class ) {
case U1:
case I1:
t = AllocTemp( I2 );
t->v.usage |= NEEDS_MEMORY | USE_MEMORY;
new_ins = MakeConvert( t, ins->result, class, I2 );
ins->result = t;
MoveSegRes( ins, new_ins );
SuffixIns( ins, new_ins );
break;
case U2:
t = AllocTemp( I4 );
t->v.usage |= NEEDS_MEMORY | USE_MEMORY;
new_ins = MakeConvert( t, ins->result, class, I4 );
ins->result = t;
MoveSegRes( ins, new_ins );
SuffixIns( ins, new_ins );
break;
case I2:
case I4:
case I8:
case U8:
ToMemory( ins, ins->result );
break;
case U4:
t = AllocTemp( XX );
t->n.size = 8;
t->v.usage |= NEEDS_MEMORY | USE_MEMORY;
new_ins = MakeMove( TempOffset(t,0,U4), ins->result, U4);
ins->result = t;
MoveSegRes( ins, new_ins );
SuffixIns( ins, new_ins );
break;
default:
break;
}
}
extern int Count87Regs( hw_reg_set regs ) {
/***********************************************
Count the number of 8087 registers named in hw_reg_set "regs".
*/
int count;
int i;
i = 0;
count = 0;
for(;;) {
if( HW_Ovlap( FPRegs[ i ], regs ) ) {
++count;
}
if( i == 7 ) break;
++i;
}
return( count );
}
extern bool FPStackIns( instruction *ins ) {
/**********************************************/
if( !_FPULevel( FPU_87 ) ) return( FALSE );
if( _OpIsCall( ins->head.opcode ) ) return( TRUE );
if( _Is87Ins( ins ) ) return( TRUE );
return( FALSE );
}
extern bool FPSideEffect( instruction *ins ) {
/*************************************************
Return TRUE if instruction "ins" is an instruction that has a side
effect, namely pushes or pops the 8087 stack.
*/
int i;
bool has_fp_reg;
if( !_FPULevel( FPU_87 ) ) return( FALSE );
/* calls require a clean stack */
if( _OpIsCall( ins->head.opcode ) ) return( TRUE );
if( !_Is87Ins( ins ) ) return( FALSE );
i = ins->num_operands;
has_fp_reg = FALSE;
while( --i >= 0 ) {
if( ins->operands[ i ]->n.class == N_REGISTER ) {
if( HW_COvlap( ins->operands[i]->r.reg, HW_FLTS ) ) {
has_fp_reg = TRUE;
}
}
}
if( ins->result != NULL ) {
if( ins->result->n.class == N_REGISTER ) {
if( HW_COvlap( ins->result->r.reg, HW_FLTS ) ) {
has_fp_reg = TRUE;
}
}
}
if( has_fp_reg ) {
if( ins->ins_flags & INS_PARAMETER ) return( TRUE );
if( ins->stk_entry != ins->stk_exit ) return( TRUE );
}
return( FALSE );
}
static bool CanStack( name *name ) {
/***************************************
Return true if "name" is a candidate for an 8087 "stack" location.
*/
instruction *first;
instruction *last;
conflict_node *conf;
if( ( name->v.usage & USE_IN_ANOTHER_BLOCK ) ) return( FALSE );
conf = name->v.conflict;
while( conf != NULL ) {
if( conf == NULL ) return( TRUE ); /* if conflict not yet allocated */
if( conf->start_block == NULL ) return( FALSE );
if( conf->ins_range.first == NULL ) return( FALSE );
if( conf->ins_range.last == NULL ) return( FALSE );
if( conf->ins_range.first == conf->ins_range.last ) return( FALSE );
first = conf->ins_range.first->head.next;
last = conf->ins_range.last;
for( ;; ) {
if( first == last ) break;
if( first->head.opcode == OP_CALL ) return( FALSE );
if( first->head.opcode == OP_CALL_INDIRECT ) return( FALSE );
first = first->head.next;
}
conf = conf->next_for_name;
}
return( TRUE );
}
static void StackShortLivedTemps( void ) {
/***************************************
Most temporaries are marked as CAN_STACK when they are back end
generated temps which are used to hold an intermediate result from
an expression tree. Some user or front end temps also fall into the
CAN_STACK category if they are defined once then used. This catches
temps that are defined in one instruction and used in the next one.
*/
conflict_node *conf;
instruction *ins1;
instruction *ins2;
name *temp;
for( conf = ConfList; conf != NULL; conf = conf->next_conflict ) {
ins1 = conf->ins_range.first;
ins2 = conf->ins_range.last;
if( ins1 == NULL ) continue;
if( ins2 == NULL ) continue;
if( !_Is87Ins( ins1 ) ) continue;
if( !_Is87Ins( ins2 ) ) continue;
if( ins1->ins_flags & INS_PARAMETER ) continue;
if( ins2->ins_flags & INS_PARAMETER ) continue;
if( ins1->head.next != ins2 ) continue;
temp = conf->name;
if( temp->n.class != N_TEMP ) continue;
if( temp->t.temp_flags & CROSSES_BLOCKS ) continue;
if( temp->t.alias != temp ) continue;
FPSetStack( temp );
}
}
static void CheckForStack( name *temp )
/*************************************
used by NoStackAcrossCalls
*/
{
if( temp->n.class != N_TEMP ) return;
if( CanStack( temp ) ) return;
temp->t.temp_flags &= ~CAN_STACK;
}
static void NoStackAcrossCalls( void ) {
/*************************************
Since a call requires the stack of the 8087 to be empty, we can't
hold a value in a stack register across a call instrution. This
routine turns off the CAN_STACK attribute in temps which live across
a call instruction. Also, we cannot stack the operands of POW, ATAN2, etc.
Run the block list, rather than the temp list for speed when we're
BlockByBlock.
*/
block *blk;
instruction *ins;
int i;
blk = HeadBlock;
while( blk != NULL ) {
ins = blk->ins.hd.next;
while( ins->head.opcode != OP_BLOCK ) {
i = ins->num_operands;
while( --i >= 0 ) {
CheckForStack( ins->operands[i] );
}
if( ins->result != NULL ) {
CheckForStack( ins->result );
}
ins = ins->head.next;
}
blk = blk->next_block;
}
}
extern type_class_def FPInsClass( instruction *ins ) {
/*******************************************************
Return FD if the instruction will use the 8087.
*/
if( !_FPULevel( FPU_87 ) ) return( XX );
if( !_Is87Ins( ins ) ) return( XX );
return( FD );
}
extern void FPSetStack( name *name ) {
/*****************************************
Turn on the CAN_STACK attribute in "name" if its ok to do so.
*/
if( name->n.class != N_TEMP ) return;
if( name->v.usage & USE_IN_ANOTHER_BLOCK ) return;
if( !_IsFloating( name->n.name_class ) ) return;
name->t.temp_flags |= CAN_STACK;
}
extern bool FPIsStack( name *name ) {
/****************************************
return TRUE if "name" is a stackable temp.
*/
if( name->n.class != N_TEMP ) return( FALSE );
if( ( name->t.temp_flags & CAN_STACK ) == EMPTY ) return( FALSE );
return( TRUE );
}
extern bool FPStackOp( name *name ) {
/****************************************
return TRUE if "name" is a stackable temp.
*/
if( !_FPULevel( FPU_87 ) ) return( FALSE );
return( FPIsStack( name ) );
}
extern void FPNotStack( name *name ) {
/*****************************************
Turn off the CAN_STACK attribute of "name". This is done whenever
an instruction is moved during an optimization, since it could cause
the value to be not at top of stack at the reference.
*/
if( name->n.class == N_TEMP ) {
name->t.temp_flags &= ~CAN_STACK;
}
}
extern bool FPIsConvert( instruction *ins ) {
/************************************************
return TRUE if "ins" is a converstion that could be handled by the 8087.
*/
type_class_def op_class;
type_class_def res_class;
if( !_FPULevel( FPU_87 ) ) return( FALSE );
if( ins->operands[ 0 ]->n.class == N_CONSTANT ) return( FALSE );
op_class = ins->operands[ 0 ]->n.name_class;
res_class = ins->result->n.name_class;
if( op_class == res_class ) return( FALSE );
if( _Is87Ins( ins ) ) return( TRUE );
return( FALSE );
}
static void FSinCos( void ) {
/*************************/
block *blk;
instruction *ins;
blk = HeadBlock;
while( blk != NULL ) {
ins = blk->ins.hd.next;
while( ins->head.opcode != OP_BLOCK ) {
if( ins->head.opcode == OP_SIN ) {
FindSinCos( ins, OP_COS );
} else if( ins->head.opcode == OP_COS ) {
FindSinCos( ins, OP_SIN );
}
ins = ins->head.next;
}
blk = blk->next_block;
}
}
static void FindSinCos( instruction *ins, opcode_defs next_op ) {
/*****************************************************************/
instruction *next;
instruction *new_ins;
name *temp;
next = ins->head.next;
for( ;; ) {
if( next->head.opcode == OP_BLOCK ) return;
if( ReDefinedBy( next, ins->operands[ 0 ] ) ) return;
if( next->head.opcode == next_op ) {
if( next->operands[ 0 ] == ins->operands[ 0 ] &&
next->type_class == ins->type_class ) break;
}
next = next->head.next;
}
temp = AllocTemp( ins->type_class );
new_ins = MakeUnary( next_op, ins->operands[0], temp, ins->type_class );
next->head.opcode = OP_MOV;
next->operands[ 0 ] = temp;
SuffixIns( ins, new_ins );
UpdateLive( ins, next );
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?