trecurse.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 438 行 · 第 1/2 页
C
438 行
for( i = 0; i < ins->num_operands; i++ ) {
if( !SafeOp( ins->operands[ i ], FALSE ) ) return( FALSE );
}
if( ins->result == ReturnValue ) {
// check to see if this value we are writing into the
// return register is the value returned from the
// recursive call we are eliminating - if so continue
if( CheckReturn( ins ) ) continue;
}
if( !SafeOp( ins->result, TRUE ) ) return( FALSE );
}
return( TRUE );
}
static pointer SafeBlock( block *blk )
/*********************************************************
Return blk if the given block, and all reachable blocks,
are safe to ignore for purposes of eliminating tail recursion,
We abuse a pointer as a boolean variable because that is
what SafeRecurse wants.
*/
{
int i;
block *dest;
block *safe;
if( blk->class & BLOCK_MARKED ) return( NULL );
blk->class |= BLOCK_MARKED;
safe = NULL;
if( SafePath( blk->ins.hd.next ) ) {
safe = blk;
for( i = 0; i < blk->targets; i++ ) {
dest = blk->edge[ i ].destination;
if( SafeRecurse( SafeBlock, dest ) == NULL ) {
safe = NULL;
break;
}
}
}
blk->class &= ~BLOCK_MARKED;
return( safe );
}
static bool ScaryOperand( name *var )
/************************************
return TRUE if the operand given has any properties which
might make elimination of tail recursion impossible
*/
{
if( var != NULL ) {
// if anything has had its address taken we chicken out
if( var->n.class == N_TEMP ) {
return( var->v.usage & USE_ADDRESS );
}
}
return( FALSE );
}
static bool ScaryConditions( void )
/**********************************
Traverse the current function and return
TRUE if there are any conditions present which
would scare us out of doing tail recursion
elimination, such as vars which have had
their addresses taken...
*/
{
block *blk;
instruction *ins;
int i;
blk = HeadBlock;
while( blk != NULL ) {
ins = blk->ins.hd.next;
while( ins->head.opcode != OP_BLOCK ) {
for( i = 0; i < ins->num_operands; i++ ) {
if( ScaryOperand( ins->operands[ i ] ) ) return( TRUE );
}
if( ScaryOperand( ins->result ) ) return( TRUE );
ins = ins->head.next;
}
blk = blk->next_block;
}
return( FALSE );
}
static bool OkayToTransCall( block *blk, instruction *call_ins )
/*******************************************************************
Check to see if it is okay to turn this call instruction
into a jump to eliminate tail recursion. To see if this
is safe, we have to follow all paths of execution to the
return block and make sure that nothing important happens
along these.
*/
{
sym_handle label;
block *dest;
int i;
instruction *parm;
instruction *ins;
bool ok;
label = AskForLblSym( CurrProc->label );
if( call_ins->operands[ CALL_OP_ADDR ]->v.symbol != label ) {
return( FALSE );
}
// check to make sure length of parm lists are the same
parm = _TR_LINK( call_ins );
for( ins = _PROC_LINK( CurrProc ); ins != NULL; ins = _TR_LINK( ins ) ) {
if( parm == NULL ) return( FALSE );
parm = _TR_LINK( parm );
}
if( parm != NULL ) return( FALSE );
// check to see if all paths are hazard-free from the
// call ins to the return block
ok = FALSE;
ReturnValue = call_ins->result;
blk->class |= BLOCK_MARKED;
// if the call is in the return block, then there are no
// paths out of this routine which do not go through it
// (except perhaps stuff calling aborts routines) so don't
// bother - better running out of stack than an infinite loop
// (besides - certain codegen stuff needs a RET block)
if( ( ( blk->class & RETURN ) == EMPTY ) &&
SafePath( call_ins->head.next ) ) {
ok = TRUE;
for( i = 0; i < blk->targets; i++ ) {
dest = blk->edge[ i ].destination;
if( SafeBlock( dest ) == NULL ) {
ok = FALSE;
break;
}
}
}
blk->class &= ~BLOCK_MARKED;
return( ok );
}
extern void TRAddParm( instruction *call_ins, instruction *parm_ins )
/************************************************************************
Add another instruction to the list of parameters for the given call
instruction.
*/
{
// if either is NULL we've had an error and should refrain from GP faulting
if( call_ins == NULL || parm_ins == NULL ) return;
_TR_LINK( parm_ins ) = (void *)_TR_LINK( call_ins );
_TR_LINK( call_ins ) = (void *)parm_ins;
}
extern void TRDeclareParm( instruction *parm_ins )
/*****************************************************
Declare another parm for the current procedure. This parm
is added to a linked list hanging off of CurrProc.
*/
{
if( parm_ins == NULL ) return;
_TR_LINK( parm_ins ) = (void *)_PROC_LINK( CurrProc );
_PROC_LINK( CurrProc ) = (void *)parm_ins;
}
extern bool TailRecursion( void )
/************************************
Eliminate any tail recursion. We assume that, for any call in
the function, we have a linked list of the parameters to that
call which was built up while creating the call instruction from
the tree, through the use of TRAddParm.
To do the deed, we scramble through the instructions backwards
following all possible paths of execution. If, on any path, we
encounter an instruction which might make tail recursion impossible
to eliminate, we give up. If we encounter a call to ourselves
before we encounter a useful instruction, we replace the call with
some code which moves the parameters into the appropriate spots
and jumps to the block just after the prologue.
*/
{
block *blk;
instruction *ins;
instruction *next;
bool changed;
changed = FALSE;
if( _IsntModel( NO_OPTIMIZATION ) &&
!ScaryConditions() && !BlockByBlock ) {
blk = HeadBlock;
while( blk != NULL ) {
ins = blk->ins.hd.next;
while( ins->head.opcode != OP_BLOCK ) {
if( ins->head.opcode == OP_CALL ) {
if( OkayToTransCall( blk, ins ) ) {
DoTrans( blk, ins );
changed = TRUE;
break;
}
}
ins = ins->head.next;
}
blk = blk->next_block;
}
}
// now reset our links and flags
blk = HeadBlock;
while( blk != NULL ) {
ins = blk->ins.hd.next;
while( ins->head.opcode != OP_BLOCK ) {
_TR_LINK( ins ) = NULL;
ins = ins->head.next;
}
blk = blk->next_block;
}
for( ins = _PROC_LINK( CurrProc ); ins != NULL; ins = next ) {
next = _TR_LINK( ins );
_TR_LINK( ins ) = NULL;
}
return( changed );
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?