unroll.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,104 行 · 第 1/3 页
C
1,104 行
if( op->i.index == orig ) {
*pop = ScaleIndex( new, op->i.base,
op->i.constant,
op->n.name_class, op->n.size,
op->i.scale, op->i.index_flags );
return( TRUE );
} else if( op->i.base == orig ) {
*pop = ScaleIndex( op->i.index, new, op->i.constant,
op->n.name_class, op->n.size,
op->i.scale, op->i.index_flags );
}
break;
case N_TEMP:
op = DeAlias( op );
if( op == orig ) {
offset = (*pop)->v.offset - op->v.offset;
*pop = TempOffset( new, offset, (*pop)->n.name_class );
return( TRUE );
}
break;
default:
if( op == orig ) {
*pop = new;
return( TRUE );
}
}
return( FALSE );
}
static void ReplaceInductionVars( block *loop, instruction *ins_list,
signed_32 scale )
/*******************************************************
Replace all occurrences of an induction var in the loop with a new
temp, and add an instruction to initialize that temp onto the ins_list.
By the time we get here, everything should be either dead or a basic
induction var. Scale should be the ordinal of the iteration we are on,
starting at 1 and incrementing each time this is called on a copy of a
loop.
*/
{
induction *ind;
name *temp;
name *var;
instruction *ins;
instruction *new_ins;
block *blk;
int i;
signed_32 adjust;
for( ind = IndVarList; ind != NULL; ind = ind->next ) {
if( _IsV( ind, IV_DEAD ) ) continue;
var = ind->name;
temp = AllocTemp( var->n.name_class );
adjust = scale * ind->plus;
new_ins = MakeBinary( OP_ADD, var, AllocS32Const( adjust ),
temp, temp->n.name_class );
for( blk = loop; blk != NULL; blk = blk->u.loop ) {
ins = blk->ins.hd.next;
for( ; ins->head.opcode != OP_BLOCK; ins = ins->head.next ) {
ReplaceName( &ins->result, var, temp );
for( i = 0; i < ins->num_operands; i++ ) {
ReplaceName( &ins->operands[i], var, temp );
}
}
}
/* have to add this after we run the list replacing vars */
PrefixIns( ins_list, new_ins );
new_ins = MakeMove( temp, var, temp->n.name_class );
SuffixIns( loop->ins.hd.prev, new_ins );
}
}
extern void DumpPtr( void * );
extern void DumpString( char * );
extern void DumpNL( void );
extern void DumpLoop( block *loop )
{
block_edge *edge;
block_num i;
DumpString( "Block\t\tBlock->u.loop\tBlock->loop_head" );
DumpNL();
DumpNL();
while( loop != NULL ) {
DumpPtr( loop );
DumpString( "\t\t" );
DumpPtr( loop->u.loop );
DumpString( "\t\t" );
DumpPtr( loop->loop_head );
DumpNL();
DumpString( "\tInputs: " );
for( edge = loop->input_edges; edge != NULL; edge = edge->next_source ) {
DumpPtr( edge->source );
DumpString( " " );
}
DumpNL();
DumpString( "\tDest: " );
for( edge = &loop->edge[ 0 ], i = 0; i < loop->targets; i++, edge++ ) {
DumpPtr( edge->destination );
DumpString( " " );
}
DumpNL();
loop = loop->u.loop;
}
}
#endif
static void LinkBlocks( block *first, block *second )
{
first->next_block = second;
second->prev_block = first;
}
static void ChainTwoLoops( loop_abstract *first, loop_abstract *last )
/*************************************************************************
Given two detached copies of a loop, link their blocks
together and join them via block->u.loop.
*/
{
LinkBlocks( first->tail, last->head );
last->head->u.loop = first->tail;
}
static block *DoUnroll( block *tail, signed_32 reps, bool replace_vars )
/**************************************************************************
Unroll the given loop (this is the tail block, and loop is connected
through blk->u.loop to the head, in which blk->u.loop == NULL) reps
times (there will be reps + 1 copies of the loop body) and replace induction
vars with new temps if replace_vars == TRUE
All of the copies made will be connected through blk->u.loop, and a
pointer to the tail of the new super-loop will be returned.
*/
{
loop_abstract *new_loops;
loop_abstract *curr;
loop_abstract *next;
loop_abstract *first;
loop_abstract *last;
block *next_block;
signed_32 i;
signed_32 size;
replace_vars = replace_vars;
size = sizeof( loop_abstract ) * reps;
// allocate an array of these abstract loop thingies
_Alloc( new_loops, size );
first = &new_loops[ 0 ];
last = &new_loops[ reps - 1 ];
// create the actual copies - they will be independant of each other
for( i = 0; i < reps; i++ ) {
curr = &new_loops[ i ];
DupLoop( tail, curr );
}
// want last copy to jump to original loop - we do it here because
// the last copy is going to get linked (via blk->u.loop) into the
// entire loop after the next pass over the array of copies
RedirectHeaderEdges( last->tail, Head );
// also, we make the original loop jump to the first of the duplicates
RedirectHeaderEdges( tail, first->head );
// now we need to make each of the loops chain to the next chap in line
// we also take this opportunity to link the various copies together via
// blk->next_block and blk->u.loop
for( i = 1; i < reps; i++ ) {
curr = &new_loops[ i - 1 ];
next = &new_loops[ i ];
RedirectHeaderEdges( curr->tail, next->head );
ChainTwoLoops( curr, next );
}
// now we just have to ram the entire thing into the block list
// for this function and link them to the original via blk->u.loop
next_block = tail->next_block;
LinkBlocks( tail, first->head );
LinkBlocks( last->tail, next_block );
first->head->u.loop = tail;
next_block = last->tail;
_Free( new_loops, size );
// and return the tail of the new super-loop
return( next_block );
}
static bool TractableCond( loop_condition *cond )
/****************************************************
To be a nice conditional exit (one we can munge) we need a comparison
between an induction variable and a loop-invariant expression. If these
conditions are present, we fill in the fields and return TRUE. If we
return FALSE, the values of cond are guaranteed to be irrelevant junk.
*/
{
bool ok;
induction *tmp;
signed_32 plus;
bool exit_true;
byte opcode;
name *n;
instruction *ins;
block *blk;
ins = cond->compare_ins;
blk = cond->compare_block;
ok = FALSE;
exit_true = FALSE;
MarkInvariants();
if( !InvariantOp( ins->operands[ 1 ] ) ) {
n = ins->operands[ 0 ];
ins->operands[ 0 ] = ins->operands[ 1 ];
ins->operands[ 1 ] = n;
RevCond( ins );
}
if( InvariantOp( ins->operands[ 1 ] ) ) {
tmp = FindIndVar( ins->operands[ 0 ] );
if( tmp != NULL ) {
cond->induction = tmp;
cond->invariant = ins->operands[ 1 ];
ok = TRUE;
}
}
UnMarkInvariants();
if( !ok ) return( FALSE );
if( _IsV( cond->induction, IV_DEAD ) ) return( FALSE );
if( ( blk->edge[ 0 ].destination->class & IN_LOOP ) != EMPTY ) {
cond->exit_edge = blk->edge[ 1 ].destination;
cond->loop_edge = blk->edge[ 0 ].destination;
if( _TrueIndex( ins ) == 1 ) {
// want loop to continue executing if condition TRUE
FlipCond( ins );
_SetBlockIndex( ins, 0, 1 );
}
} else {
cond->exit_edge = blk->edge[ 0 ].destination;
cond->loop_edge = blk->edge[ 1 ].destination;
if( _TrueIndex( ins ) == 0 ) {
// want loop to continue executing if condition TRUE
FlipCond( ins );
_SetBlockIndex( ins, 1, 0 );
}
}
plus = cond->induction->plus;
opcode = ins->head.opcode;
switch( opcode ) {
case OP_CMP_NOT_EQUAL:
if( plus < 0 ) {
cond->opcode = OP_CMP_GREATER;
} else {
cond->opcode = OP_CMP_LESS;
}
break;
case OP_CMP_GREATER:
case OP_CMP_GREATER_EQUAL:
cond->opcode = opcode;
if( plus >= 0 ) ok = FALSE;
break;
case OP_CMP_LESS:
case OP_CMP_LESS_EQUAL:
cond->opcode = opcode;
if( plus <= 0 ) ok = FALSE;
break;
case OP_CMP_EQUAL:
case OP_BIT_TEST_TRUE:
case OP_BIT_TEST_FALSE:
ok = FALSE;
break;
default:
Zoiks( ZOIKS_113 );
}
return( ok );
}
extern block *AddBlocks( block *insertion_point, block *block_list )
/**********************************************************************
Insert the list of blocks after the given insertion point.
*/
{
block *last;
last = block_list;
while( last->next_block != NULL ) last = last->next_block;
last->next_block = insertion_point->next_block;
if( last->next_block != NULL ) {
last->next_block->prev_block = last;
}
block_list->prev_block = insertion_point;
insertion_point->next_block = block_list;
return( last );
}
extern void RemoveIns( instruction *ins )
/********************************************
Remove the ins from the instruction ring. Does not take
into account live info or anything else like that.
*/
{
instruction *next;
instruction *prev;
next = ins->head.next;
prev = ins->head.prev;
next->head.prev = prev;
prev->head.next = next;
ins->head.next = NULL;
ins->head.prev = NULL;
}
static block *MakeNonConditional( block *butt, block_edge *edge )
/*******************************************************************
If butt is conditional, create a new block which is
in between the conditional block and the head of the
current loop. We need a nonconditional block so that
we can append instructions to it when hoisting the
condition to the top of the loop.
*/
{
block *blk;
if( ( butt->class & CONDITIONAL ) != EMPTY ) {
blk = MakeBlock( AskForNewLabel(), 1 );
blk->class = JUMP | IN_LOOP;
blk->id = NO_BLOCK_ID;
blk->gen_id = butt->gen_id;
blk->ins.hd.line_num = 0;
blk->next_block = butt->next_block;
if( blk->next_block != NULL ) {
blk->next_block->prev_block = blk;
}
blk->prev_block = butt;
butt->next_block = blk;
blk->loop_head = Head;
PointEdge( &blk->edge[ 0 ], edge->destination );
MoveEdge( edge, blk );
UnMarkLoop();
MarkLoop();
return( blk );
}
return( butt );
}
static int ExitEdges( block *head )
/***************************************
Return the number of edges in the loop with the given head which
exit the loop.
*/
{
int count;
block *blk;
count = 0;
for( blk = HeadBlock; blk != NULL; blk = blk->next_block ) {
if( blk->loop_head == head || blk == head ) {
if( blk->class & LOOP_EXIT ) count++;
}
}
return( count );
}
extern bool CanHoist( block *head )
/**************************************
Figure out if we can hoist the condition of a loop to the top of
the loop. Basically, we can do this as long as there are no
if's between the head and the comparison instruction.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?