i86ldstr.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 622 行 · 第 1/2 页
C
622 行
new_l->operands[ 1 ] = (void *)new_h;
new_l->ins_flags |= INS_SPLIT;
new_h->ins_flags |= INS_SPLIT;
SuffixIns( ins, new_l );
SuffixIns( ins, new_h );
FreeIns( ins );
new_h = MakeGeneratable( new_h );
new_l = MakeGeneratable( new_l );
return( TRUE );
}
static void RestoreMem16Move( instruction *ins )
/***************************************************
Put a 16-bit move back together in case we were
unable to schedule the one-byte moves into being
faster. See comment about cheesiness above.
*/
{
instruction *other;
hw_reg_set full;
if( ins->head.next == (instruction *)ins->operands[ 1 ] ) {
other = ins->head.next;
} else if( ins->head.prev == (instruction *)ins->operands[ 1 ] ) {
other = ins->head.prev;
} else {
return;
}
if( ( other->ins_flags & INS_SPLIT ) == EMPTY ) return;
if( ins->result->n.class == N_REGISTER && other->result->n.class == N_REGISTER ) {
full = HW_EMPTY;
HW_TurnOn( full, other->result->r.reg );
HW_TurnOn( full, ins->result->r.reg );
ins->result = AllocRegName( full );
ins->type_class = U2;
FreeIns( other );
}
}
static bool FixMem16Moves( void )
/******************************
Look for 16-bit mem moves and turn them into two 1-byte
mem moves, so as to escape the dreaded size override. If
we are unable to schedule them, we will crunch them back
up in LdStCompress. We want to do this as a separate pass
so that we can fix moves generated by LdStAlloc.
*/
{
block *blk;
instruction *ins;
bool changed;
instruction *next;
if( OptForSize != 0 ) return( FALSE );
if( !_CPULevel( CPU_586 ) ) return( FALSE );
changed = FALSE;
for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) {
for( ins=blk->ins.hd.next; ins->head.opcode!=OP_BLOCK; ins=next ) {
next = ins->head.next; /* list is shifting underneath us */
if( ins->head.opcode == OP_MOV && TypeClassSize[ ins->type_class ] == 2 ) {
switch( ins->operands[ 0 ]->n.class ) {
case N_MEMORY:
case N_INDEXED:
case N_TEMP:
if( ins->ins_flags & INS_SPLIT ) {
changed |= SplitMem16Move( ins );
}
default:
break;
}
}
}
}
return( changed );
}
static void CompressMem16Moves( void )
/***********************************
*/
{
block *blk;
instruction *ins;
if( !_CPULevel( CPU_586 ) ) return;
for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) {
for( ins = blk->ins.hd.next; ins->head.opcode != OP_BLOCK; ins = ins->head.next ) {
RestoreMem16Move( ins );
}
}
}
#else
static bool FixMem16Moves( void ) { return( FALSE ); }
static void CompressMem16Moves( void ) {}
#endif
extern bool LdStAlloc( void )
/*******************************
Look for non-move operations with memory operands and change them
into RISC style load/store instructions. This helps on the 486 and
up because of instruction scheduling. Return a boolean saying whether
anything got twiddled so the register scoreboarder can be run again.
This routine also required for optimization of assignment
of one copy of same constant to multiple memory locations using
temporary register.
*/
{
block *blk;
instruction *ins;
instruction *next;
bool changed;
RoverByte = NULL;
RoverWord = NULL;
RoverDouble = NULL;
/* 2006-04-25 RomanT:
Run RISCifier for all modes, but sometimes (depending on CPU and
optimization) prefer shorter non-RISC version of instructions.
*/
PreferSize = FALSE;
if( OptForSize > 50 ) {
PreferSize = TRUE;
}
if( !_CPULevel( CPU_486 ) ) {
PreferSize = TRUE;
}
#if 0 /* You can optionally disable riscifer when optimizing for size */
if (PreferSize) return FALSE;
#endif
changed = FALSE;
for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) {
for( ins=blk->ins.hd.next; ins->head.opcode!=OP_BLOCK; ins=next ) {
next = ins->head.next; /* list is shifting underneath us */
if( LoadStoreIns( ins ) ) {
UpdateLive( blk->ins.hd.next, blk->ins.hd.prev );
changed = TRUE;
}
}
}
changed |= FixMem16Moves();
return( changed );
}
static bool CanCompressResult( instruction *ins,
name *prev_op0, instruction *next,
name **presult, name **popnd )
{
int i;
if( presult == NULL ) {
return FALSE;
}
if( HW_Ovlap( (*presult)->r.reg, next->head.next->head.live.regs ) ) {
return FALSE;
}
if( popnd != NULL ) {
if( *popnd != *presult ) return FALSE;
if( next->result != prev_op0 ) return FALSE;
} else {
for( i = 0; i < ins->num_operands; ++i ) {
if( ins->operands[i]->n.class != N_REGISTER ) {
continue;
}
if( HW_Ovlap( ins->operands[i]->r.reg, ins->result->r.reg ) ) {
return FALSE;
}
}
}
return TRUE;
}
static void CompressIns( instruction *ins )
/**************************************************
See if a RISCified instruction 'ins' is still in CISCifyable form and
do it to it.
*/
{
instruction *next;
instruction *prev;
name *prev_op0;
name **presult;
name **popnd;
name **preplace;
name *replacement;
int i;
int num_op;
if( !(ins->ins_flags & INS_RISCIFIED) ) return;
switch( ins->head.opcode ) {
case OP_PUSH:
case OP_POP:
/* If size preferable then push must be compacted */
if( PreferSize ) break;
/* It's better to use a register for PUSH/POP on a 486 */
if( _CPULevel( CPU_486 ) ) return;
default:
break;
}
next = ins->head.next;
if( next->head.opcode != OP_MOV || next->operands[0]->n.class != N_REGISTER ) {
next = NULL;
}
prev = ins->head.prev;
prev_op0 = prev->operands[0];
if( prev->head.opcode != OP_MOV || prev->result->n.class != N_REGISTER ) {
/* 2006-10-14 RomanT
* Special case: "MOV REG, 0" usually reduced to "XOR REG, REG",
* changing opcode and confusing deriscifier. XOR is shorter then
* non-optimized 16- or 32-bit MOV, but worse for 8-bit moves
* (same size, two commands, extra register occupied).
*
* Handling these XOR's everywhere is boring. It must be rewriten
* in some other way. May be we shall instroduce G_SMARTMOV which must
* be resolved to XOR/AND 0/OR -1/XOR+INC only during generation
* of machine code.
*/
if ( prev->head.opcode == OP_XOR &&
prev_op0 == prev->operands[1] &&
TypeClassSize[ prev->type_class ] == 1
) {
prev_op0 = AllocIntConst( 0 ); /* fake "MOV RESULT, 0" */
}
else {
prev = NULL;
}
}
presult = NULL;
popnd = NULL;
if( next != NULL && ins->result == next->operands[0] ) {
presult = &ins->result;
}
if( prev != NULL ) {
// 2005-04-05 RomanT
// Do not use ins->num_operands here, otherwise we'll falsely trigger
// compression for segment operand of instruction which we shouldn't.
// (bug #442)
num_op = NumOperands( ins );
for( i = 0; i < num_op; ++i ) {
if( prev->result == ins->operands[i] ) {
popnd = &ins->operands[i];
}
}
}
// 2006-05-19 RomanT
// Even if compression of result failed, we must try to compress operands
if( CanCompressResult( ins, prev_op0, next, presult, popnd ) ) {
replacement = next->result;
preplace = presult;
} else {
presult = NULL; // Forget about result (don't free ins below!)
if( popnd == NULL ) return;
// make sure that the REG is not used in any operands besides
// the one which we are thinking of replacing BBB - Dec 4, 1993
for( i = 0; i < ins->num_operands; i++ ) {
if( popnd == &ins->operands[ i ] ) continue;
if( ins->operands[ i ]->n.class != N_REGISTER ) continue;
if( HW_Ovlap( ins->operands[ i ]->r.reg, (*popnd)->r.reg ) ) {
return;
}
}
if( HW_Ovlap( (*popnd)->r.reg, ins->head.next->head.live.regs ) ) {
return;
}
replacement = prev_op0;
preplace = popnd;
}
if( !ChangeIns( ins, replacement, preplace, CHANGE_GEN | CHANGE_ALL ) ) return;
if( presult != NULL ) {
DupSeg( next, ins );
FreeIns( next );
}
if( popnd != NULL ) {
DupSeg( prev, ins );
FreeIns( prev );
}
UpdateLive( ins->head.prev, ins );
}
extern void LdStCompress( void )
/**********************************
Compress any load/store sequences generated by LdStAlloc back
into memory ops if no optimizations made use of them.
*/
{
block *blk;
instruction *ins;
/* Note: LdStAlloc() must be called first to set PreferSize variable */
CompressMem16Moves();
for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) {
ins = blk->ins.hd.next;
while( ins->head.opcode != OP_BLOCK ) {
CompressIns( ins );
ins = ins->head.next;
}
}
DeadInstructions();
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?