optimize.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 474 行 · 第 1/2 页
C
474 行
}
static void PushInsForward( block *blk ) {
/*********************************************
Try pushing down each instruction in the program.
*/
instruction *ins;
instruction *prev;
instruction *next;
ins = blk->ins.hd.prev; /* move backwards through instructions*/
for(;;) {
if( ins->head.opcode == OP_BLOCK ) break;
prev = ins->head.prev;
next = CanMoveAfter( ins );
if( next != NULL ) {
/* Remove 'ins' from its current position*/
ins->head.next->head.prev = ins->head.prev;
ins->head.prev->head.next = ins->head.next;
/* Link 'ins' before 'next'*/
ins->head.prev = next->head.prev;
next->head.prev = ins;
ins->head.prev->head.next = ins;
ins->head.next = next;
}
ins = prev;
}
}
extern bool SameThing( name *x, name *y ) {
/**********************************************
returns TRUE if "x" and "y" are the same thing. IE: N_MEMORY
names which are associated with the same front end symbol or
N_TEMP names which are aliases of each other. Two temporaries
which are "stackable" are considered to be the same thing
since they may (probably will) both end up on the 8087 stack.
*/
if( x == y ) return( TRUE );
if( x == NULL || y == NULL ) return( FALSE );
if( FPIsStack( x ) && FPIsStack( y ) ) return( TRUE );
if( x->n.class == N_MEMORY
&& y->n.class == N_MEMORY
&& x->v.symbol == y->v.symbol ) return( TRUE );
if( x->n.class == N_TEMP && y->n.class == N_TEMP ) {
if( x->t.v.id != y->t.v.id ) return( FALSE );
if( !( x->t.temp_flags & ALIAS )
&& !( y->t.temp_flags & ALIAS ) ) return( FALSE );
return( TRUE );
}
return( FALSE );
}
extern void DeadTemps() {
/****************************
Using the information contained in each N_TEMP, delete any instruction
whose result is a temporary that isnt used again. This is only a very
crude hack of dead code, since it only gets temporaries which are local
to a basic block and are only defined. Its designed to get rid of
dummy instructions generated to preserve the value of an assignment
operator. For example, *x = *y generates:
MOV [y] => [x]
MOV [x] => temp <- this usually doesn't get used later
*/
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( SideEffect( ins ) == FALSE
&& _IsntIns( ins, SIDE_EFFECT )
&& ins->result != NULL
&& ins->result->n.class == N_TEMP
&& ( ins->result->v.usage
&(USE_ADDRESS|HAS_MEMORY|USE_WITHIN_BLOCK|USE_IN_ANOTHER_BLOCK) )
== EMPTY ) {
FreeIns( ins );
}
ins = next;
}
blk = blk->next_block;
}
}
static bool IsDeadIns( block *blk, instruction *ins, instruction *next ) {
/*****************************************************************************
returns TRUE if an instruction is assigning to a name which is not
live immediately following instruction "ins".
*/
conflict_node *conf;
name *op;
op = ins->result;
if( op == NULL ) return( FALSE );
// if( op->n.class != N_TEMP ) return( FALSE );
if( op->v.usage & USE_ADDRESS ) return( FALSE );
if( SideEffect( ins ) ) return( FALSE );
conf = FindConflictNode( op, blk, ins );
if( conf == NULL ) return( FALSE );
if( _LBitEmpty( conf->id.within_block )
&& _GBitEmpty( conf->id.out_of_block ) ) {
return( FALSE );
}
if( _LBitOverlap( conf->id.within_block, next->head.live.within_block ) ) {
return( FALSE );
}
if( _GBitOverlap( conf->id.out_of_block, next->head.live.out_of_block ) ) {
return( FALSE );
}
return( TRUE );
}
extern void AxeDeadCode() {
/******************************
This is like DeadTemps, but it uses the live information in order
to discover whether an instruction is assigning to a variable that
dies immediately following. If we change anything here, we redo
the live information (that's not very expensive).
*/
/* delete instructions which assign to temporaries which will not be*/
/* used again before they are reassigned (ie: are not live after the instruction*/
block *blk;
instruction *ins;
instruction *next;
instruction *kill;
bool change;
/* Reuse field, it's useless for killed instruction */
#define _INS_KILL_LINK( ins ) ( ins )->u2.cse_link
for(;;) {
kill = NULL;
change = FALSE;
blk = HeadBlock;
while( blk != NULL ) {
ins = blk->ins.hd.next;
while( ins->head.opcode != OP_BLOCK ) {
next = ins->head.next;
if( IsDeadIns( blk, ins, next ) ) {
ins->result = NULL;
change = TRUE;
if( _IsntIns( ins, SIDE_EFFECT ) ) {
/*
* 2005-05-18 RomanT
* Do not free instruction immediately, or conflict
* edges will point to nowhere. Add them to kill list.
*/
_INS_KILL_LINK( ins ) = kill;
kill = ins;
} else if( _OpIsCondition( ins->head.opcode ) ) {
_SetBlockIndex( ins, NO_JUMP, NO_JUMP );
}
}
ins = next;
}
blk = blk->next_block;
}
if( change == FALSE ) break;
FreeConflicts();
/* Now it's safe to free instructions without problems with edges */
while ( kill ) {
next = _INS_KILL_LINK( kill );
FreeIns( kill );
kill = next;
}
NullConflicts(EMPTY);
FindReferences();
MakeConflicts();
MakeLiveInfo();
}
}
extern void DeadInstructions() {
/***********************************
This is called after register allocation. It frees up any
instructions whose generate table says G_NO (don't generate me).
*/
block *blk;
blk = HeadBlock;
while( blk != NULL ) {
FreeJunk( blk );
blk = blk->next_block;
}
}
extern void PushPostOps() {
/******************************
This routine tries to push add and subtract instructions
forward in the basic block. The reason for this is that
it untangles post increment code allowing for copy propagation
and code elimination. Take *x++ = *y++ for example
Before: After: With copy propagation:
MOV x => t1 MOV x => t1 MOV x => t1 (useless)
MOV y => t2 MOV y => t2 MOV y => t2 (useless)
ADD x, 1 => x MOV [t2] => [t1] MOV [y] => [x]
ADD y, 1 => y ADD x,1 => x ADD x,1 => x
MOV [t2] => [t1] ADD y,1 => y ADD y,1 => y
*/
/* Perform instruction optimizations*/
block *blk;
blk = HeadBlock;
while( blk != NULL ) {
PushInsForward( blk );
blk = blk->next_block;
}
PropagateMoves();
Renumber();
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?