You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

217 lines
4.8 KiB

/*
* jit-live.c - Liveness analysis for function bodies.
*
* Copyright (C) 2004 Southern Storm Software, Pty Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "jit-internal.h"
/*
* Compute liveness information for a basic block.
*/
static void compute_liveness_for_block(jit_block_t block)
{
jit_insn_iter_t iter;
jit_insn_t insn;
jit_value_t dest;
jit_value_t value1;
jit_value_t value2;
int flags;
/* Scan backwards to compute the liveness flags */
jit_insn_iter_init_last(&iter, block);
while((insn = jit_insn_iter_previous(&iter)) != 0)
{
/* Skip NOP instructions, which may have arguments left
over from when the instruction was replaced, but which
are not relevant to our liveness analysis */
if(insn->opcode == JIT_OP_NOP)
{
continue;
}
/* Fetch the value parameters to this instruction */
flags = insn->flags;
if((flags & JIT_INSN_DEST_OTHER_FLAGS) == 0)
{
dest = insn->dest;
if(dest && dest->is_constant)
{
dest = 0;
}
}
else
{
dest = 0;
}
if((flags & JIT_INSN_VALUE1_OTHER_FLAGS) == 0)
{
value1 = insn->value1;
if(value1 && value1->is_constant)
{
value1 = 0;
}
}
else
{
value1 = 0;
}
if((flags & JIT_INSN_VALUE2_OTHER_FLAGS) == 0)
{
value2 = insn->value2;
if(value2 && value2->is_constant)
{
value2 = 0;
}
}
else
{
value2 = 0;
}
/* Record the liveness information in the instruction flags */
flags &= ~JIT_INSN_LIVENESS_FLAGS;
if(dest)
{
if(dest->live)
{
flags |= JIT_INSN_DEST_LIVE;
}
if(dest->next_use)
{
flags |= JIT_INSN_DEST_NEXT_USE;
}
}
if(value1)
{
if(value1->live)
{
flags |= JIT_INSN_VALUE1_LIVE;
}
if(value1->next_use)
{
flags |= JIT_INSN_VALUE1_NEXT_USE;
}
}
if(value2)
{
if(value2->live)
{
flags |= JIT_INSN_VALUE2_LIVE;
}
if(value2->next_use)
{
flags |= JIT_INSN_VALUE2_NEXT_USE;
}
}
insn->flags = (short)flags;
/* Set the destination to "not live, no next use" */
if(dest)
{
if((flags & JIT_INSN_DEST_IS_VALUE) == 0)
{
if(!(dest->next_use) && !(dest->live))
{
/* There is no next use of this value and it is not
live on exit from the block. So we can discard
the entire instruction as it will have no effect */
insn->opcode = (short)JIT_OP_NOP;
continue;
}
dest->live = 0;
dest->next_use = 0;
}
else
{
/* The destination is actually a source value for this
instruction (e.g. JIT_OP_STORE_RELATIVE_*) */
dest->live = 1;
dest->next_use = 1;
}
}
/* Set value1 and value2 to "live, next use" */
if(value1)
{
value1->live = 1;
value1->next_use = 1;
}
if(value2)
{
value2->live = 1;
value2->next_use = 1;
}
}
/* Re-scan the block to reset the liveness flags on all non-temporaries
because we need them in the original state for the next block */
jit_insn_iter_init_last(&iter, block);
while((insn = jit_insn_iter_previous(&iter)) != 0)
{
flags = insn->flags;
if((flags & JIT_INSN_DEST_OTHER_FLAGS) == 0)
{
dest = insn->dest;
if(dest && !(dest->is_constant) && !(dest->is_temporary))
{
dest->live = 1;
dest->next_use = 0;
}
}
if((flags & JIT_INSN_VALUE1_OTHER_FLAGS) == 0)
{
value1 = insn->value1;
if(value1 && !(value1->is_constant) && !(value1->is_temporary))
{
value1->live = 1;
value1->next_use = 0;
}
}
if((flags & JIT_INSN_VALUE2_OTHER_FLAGS) == 0)
{
value2 = insn->value2;
if(value2 && !(value2->is_constant) && !(value2->is_temporary))
{
value2->live = 1;
value2->next_use = 0;
}
}
}
}
void _jit_function_compute_liveness(jit_function_t func)
{
jit_block_t block = func->builder->first_block;
while(block != 0)
{
/* If the block is never entered, then replace it with empty */
if(!(block->entered_via_top) && !(block->entered_via_branch))
{
block->last_insn = block->first_insn - 1;
}
/* Perform peephole optimization on branches to branches */
_jit_block_peephole_branch(block);
/* Compute the liveness flags for the block */
compute_liveness_for_block(block);
/* Move on to the next block in the function */
block = block->next;
}
}