/* src/vm/jit/allocator/lsra.c - linear scan register allocator

   Copyright (C) 2005, 2006, 2007, 2008
   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO

   This file is part of CACAO.

   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, 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., 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301, USA.

*/


#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <limits.h>

#include "arch.h"
#include "md-abi.h"

#include "vm/types.h"

#include "mm/memory.h"
#include "toolbox/logging.h"
#include "vm/builtin.h"
#include "vm/exceptions.h"
#include "vm/resolve.h"
#include "vm/options.h"
#include "vm/statistics.h"
#include "vm/stringlocal.h"
#include "vm/jit/abi.h"
#include "vm/jit/reg.h"
#include "vm/jit/allocator/liveness.h"
#include "vm/jit/allocator/lsra.h"

#ifdef USAGE_COUNT
extern char **prof_m_names;
extern u4   **prof_bb_freq;
extern int  prof_size;
#endif

/* function prototypes */
void lsra_init(jitdata *);
void lsra_setup(jitdata *);
void lsra_main(jitdata *);

void lsra_reg_setup(jitdata *, struct lsra_register *, struct lsra_register * );
void lsra_calc_lifetime_length(jitdata *);
void _lsra_main( jitdata *, int *, int, struct lsra_register *, int *);
void lsra_expire_old_intervalls(jitdata *, struct lifetime *,
								struct lsra_register *);
void spill_at_intervall(jitdata *, struct lifetime *);
void lsra_add_active(struct lifetime *, struct lifetime **, int *);
void _lsra_expire_old_intervalls(jitdata *, struct lifetime *,
								 struct lsra_register *, struct lifetime **,
								 int *);
void _spill_at_intervall(struct lifetime *, struct lifetime **, int *);

void lsra_alloc(jitdata *, int *, int, int *);
int lsra_getmem(struct lifetime *, struct freemem *, int *);
struct freemem *lsra_getnewmem(int *);
void lsra_setflags(int *, int);

#ifdef LSRA_DEBUG_VERBOSE 
void lsra_dump_stack(stackelement_t* );
void print_lifetimes(jitdata *, int *, int);
#endif

#if !defined(LV)
void lsra_scan_registers_canditates(jitdata *, int);
void lsra_join_lifetimes(jitdata *, int);

void _lsra_new_stack( lsradata *, stackelement_t* , int , int, int);
void _lsra_from_stack(lsradata *, stackelement_t* , int , int, int);
void lsra_add_ss(struct lifetime *, stackelement_t* );
void lsra_usage_local(lsradata *, s4 , int , int , int , int );
#endif



bool lsra(jitdata *jd)
{
#if defined(ENABLE_STATISTICS)
	lsradata *ls;
	int locals_start;
	int i,j;
#endif	
#if defined(LSRA_DEBUG_CHECK)
	methodinfo   *m;
	int      b_index;
	stackelement_t* in,out;
	int      ind, outd;
#endif

#if defined(LSRA_DEBUG_CHECK)
	m  = jd->m;
	b_index = 0;
	while (b_index < m->basicblockcount ) {

		if (m->basicblocks[b_index].flags >= BBREACHED) {

			in=m->basicblocks[b_index].instack;
			ind=m->basicblocks[b_index].indepth;
			for (;ind != 0;in=in->prev, ind--) {
				                        /* ARGVAR or LOCALVAR in instack is ok*/
#if 0
				if (in->varkind == ARGVAR) printf("ARGVAR in instack: \n");
				if (in->varkind == LOCALVAR) printf("LOCALVAR in instack\n");
#endif
			}
			out=m->basicblocks[b_index].outstack;
			outd=m->basicblocks[b_index].outdepth;
			for (;outd != 0;out=out->prev, outd--) {
				if (out->varkind == ARGVAR)
					{ log_text("ARGVAR in outstack\n"); assert(0); }
				if (out->varkind == LOCALVAR)
					{ log_text("LOCALVAR in outstack\n"); assert(0); }
			}
		}
			b_index++;
	}
#endif

	jd->ls = DNEW(lsradata);
	lsra_init(jd);
	lsra_setup(jd);

#if defined(ENABLE_STATISTICS)
	/* find conflicts between locals for statistics */
	if (opt_stat) {
		ls = jd->ls;
		/* local Variable Lifetimes are at the end of the lifetime array and  */
		/* have v_index >= 0 */
		for (locals_start = ls->lifetimecount-1; (locals_start >=0) && 
			(ls->lifetime[ls->lt_used[locals_start]].v_index >= 0);
			 locals_start--);
		for (i=locals_start + 1; i < ls->lifetimecount; i++)
			for (j=i+1; j < ls->lifetimecount; j++)
				if ( !((ls->lifetime[ls->lt_used[i]].i_end 
					   < ls->lifetime[ls->lt_used[j]].i_start) 
					|| (ls->lifetime[ls->lt_used[j]].i_end < 
					   ls->lifetime[ls->lt_used[i]].i_start)) )
					count_locals_conflicts += 2;
	 }
#endif
	/* Run LSRA */
	lsra_main(jd);

	/* everything's ok */

	return true;
}

/* sort Basic Blocks using Depth First Search in reverse post order in */
/* ls->sorted.  */
void lsra_DFS(jitdata *jd) {
	int *stack;
	int *visited;
	int stack_top;
	bool not_finished;
	int i,p;
    struct _list *succ;

	methodinfo *m;
	lsradata   *ls;

	m  = jd->m;
	ls = jd->ls;

	stack = DMNEW( int, m->basicblockcount + 1);
	visited = (int *)DMNEW( int, m->basicblockcount + 1);
	for (i = 0; i <= m->basicblockcount; i++) {
		visited[i] = 0;
		ls->sorted[i]=-1;
		ls->sorted_rev[i]=-1;
	}

    stack[0] = 0; /* start with Block 0 */
	stack_top = 1;
	visited[0] = ls->num_pred[0]; /* Start Block is handled right and can be */
	                              /* put in sorted */
	p = 0; 
	not_finished = true;
	while (not_finished) {
		while (stack_top != 0) {
			stack_top--;
			i = stack[stack_top];
			ls->sorted[p]=i;
			p++; /*--;*/
			for (succ = ls->succ[i]; succ != NULL; succ = succ->next) {
				visited[succ->value]++;
				if (visited[succ->value] == ls->num_pred[succ->value]) {
					/* push the node on the stack, only if all ancestors have */
					/* been visited */
					stack[stack_top] = succ->value;
					stack_top++;
				}
			}
		}
		not_finished = false;
		for (i=1; i <= m->basicblockcount; i++) {
			/* search for visited blocks, which have not reached the num_pred */
			/* and put them on the stack -> happens with backedges */
			if ((visited[i] != 0) && (visited[i] < ls->num_pred[i])) {
				stack[stack_top] = i;
				stack_top++;
				visited[i] = ls->num_pred[i];
				not_finished=true;
				break;
			}
		}
	}
}

void lsra_get_backedges_(lsradata *ls, int basicblockcount) {
	struct _list *s;
	struct _backedge *n;
	struct _backedge *_backedges;
	int    i;


	_backedges = NULL;

	/* now look for backedges */
	ls->backedge_count = 0;
	for(i=0; i < basicblockcount; i++) {
		if (ls->sorted[i] != -1)
			for(s=ls->succ[ls->sorted[i]]; s != NULL; s=s->next) {
				if (i >= ls->sorted_rev[s->value]) {
					n=DNEW(struct _backedge);
					n->start = max(i, ls->sorted_rev[s->value]);
					n->end = min(i, ls->sorted_rev[s->value]);
					n->next = _backedges;
					_backedges = n;
					ls->backedge_count++;
				}
			}
	}
	/* put _backedges in ls->backedge array */
	ls->backedge = DMNEW(struct _backedge *, ls->backedge_count);
	for (n=_backedges, i=0; n != NULL; n=n->next, i++) {
		ls->backedge[i] = n;
		ls->backedge[i]->nesting = 1;
	}
}

void lsra_get_nesting(jitdata *jd) {
	methodinfo *m;
	lsradata   *ls;
	int    i,j, end;
	struct _backedge *n;

	m = jd->m;
	ls = jd->ls;

	for (i=0; i <= m->basicblockcount; i++)
		if (ls->sorted[i] != -1) 
			ls->sorted_rev[ls->sorted[i]]=i;

	lsra_get_backedges_(ls, m->basicblockcount + 1);
	/* - sort backedge by increasing end: */
	for (i=0; i < ls->backedge_count; i++)
		for (j=i+1; j < ls->backedge_count; j++) 
			if ((ls->backedge[i]->end > ls->backedge[j]->end) ||     /* -> swap */
				  ((ls->backedge[i]->end == ls->backedge[j]->end) &&
				   (ls->backedge[i]->start > ls->backedge[j]->start) )) {
				n=ls->backedge[i];
				ls->backedge[i]=ls->backedge[j];
				ls->backedge[j]=n;
			}

	/* create ls->nesting */
	/* look for nesting depth (overlapping backedges*/
	for (i=0; i < ls->backedge_count - 1; i++) {
		for (j = i + 1; (j < ls->backedge_count) &&
				 (ls->backedge[i]->start >= ls->backedge[j]->end); j++)
			ls->backedge[j]->nesting += ls->backedge[i]->nesting;
	}

    i = 0;
    j = 0;
	while ( (i < m->basicblockcount + 1)  ) {
		if (j < ls->backedge_count) {
			while ( i < ls->backedge[j]->end ) {
				ls->nesting[i] = 0;
				i++;
			}
			if ( (j+1) < ls->backedge_count)
				end = min(ls->backedge[j]->start, ls->backedge[j+1]->end - 1);
			else
				end = ls->backedge[j]->start;
			while (i <= end) {
				ls->nesting[i] = ls->backedge[j]->nesting;
				i++;
			}
			j++;
		} else {
			ls->nesting[i] = 0;
			i++;
		}
	}

#ifdef LSRA_DEBUG_VERBOSE
	if (compileverbose) {
	printf("sorted: \n");
	for (i=0; i < ls->backedge_count; i++)
		printf("Backedge: %i - %i, %i - %i\n", ls->sorted[ls->backedge[i]->start], ls->sorted[ls->backedge[i]->end], ls->backedge[i]->start, ls->backedge[i]->end);
	printf("Nesting Level \n");
	for (i=0; i<m->basicblockcount; i++) printf(" %3li", ls->nesting[i]);
	printf("\n");
	}
#endif
	for (i=0; i <= m->basicblockcount; i++) {
		ls->sorted_rev[i] = -1;
		ls->nesting[i] = 1+ls->nesting[i]*ls->nesting[i]*10;
	}
}

void lsra_get_backedges(jitdata *jd) {
	methodinfo *m;
	lsradata   *ls;
	struct _list **next;
	struct _backedge *n;
	int    i,j;
	bool   merged;

	m  = jd->m;
	ls = jd->ls;

	/* first remove artificial end basicblock from ls->sorted, succ and pred */
    j=-1;
	for (i=0; i < m->basicblockcount; i++) {
		for (next=&(ls->succ[i]); *next != NULL; next=&((*next)->next)) {
			if ( (*next)->value == m->basicblockcount ) {
				/* artificial end bb found */
				*next = (*next)->next;
				if (*next == NULL) break;
			}
		}
		for (next=&(ls->pred[i]); *next != NULL; next=&((*next)->next)) {
			if ( (*next)->value == m->basicblockcount ) {
				/* artificial end bb found */
				*next = (*next)->next;
				if (*next == NULL) break;
			}
		}
		if (j==-1)
			if (ls->sorted[i] == m->basicblockcount) j=i;
  	}

	/* if an artificial end block was removed -> change ls->sorted accordingly*/
	if (j!=-1)
		for (i=j+1; i <= m->basicblockcount; i++) {
			ls->sorted[i-1] = ls->sorted[i];
			ls->nesting[i-1] = ls->nesting[i];
		}

	for (i=0; i < m->basicblockcount; i++)
		if (ls->sorted[i] != -1) 
			ls->sorted_rev[ls->sorted[i]]=i;

	lsra_get_backedges_(ls, m->basicblockcount);

	/* - sort backedge by increasing start */
	for (i=0; i < ls->backedge_count; i++)
		for (j=i+1; j < ls->backedge_count; j++) 
			if (ls->backedge[i]->start > ls->backedge[j]->start) {     
				/* -> swap */
				n = ls->backedge[i];
				ls->backedge[i] = ls->backedge[j];
				ls->backedge[j] = n;
			}

#ifdef LSRA_DEBUG_VERBOSE
	if (compileverbose) {
		printf("sorted: \n");
		for (i=0; i < ls->backedge_count; i++)
			printf("Backedge: %i - %i, %i - %i\n", 
				   ls->sorted[ls->backedge[i]->start], 
				   ls->sorted[ls->backedge[i]->end], ls->backedge[i]->start, 
				   ls->backedge[i]->end);
		printf("Nesting Level \n");
		for (i=0; i<m->basicblockcount; i++) printf(" %3li", ls->nesting[i]);
		printf("\n");
	}
#endif

	merged = true;
	/* - merge overlapping backedges */
	while (merged) {
		merged = false;
		for (i=0; i < ls->backedge_count-1; i++) {
			if (ls->backedge[i] != NULL) {
				for (j = i + 1; (j < ls->backedge_count) && (ls->backedge[j] == NULL); j++ );
				if (j != ls->backedge_count) {
					if (ls->backedge[i]->start >= ls->backedge[j]->end) {
						merged = true;
						/* overlapping -> merge */
						ls->backedge[j]->end = min (ls->backedge[j]->end, 
												    ls->backedge[i]->end);
						ls->backedge[i] = NULL;
					}
				}
			}
		}
	}
#ifdef LSRA_DEBUG_VERBOSE
	if (compileverbose) {
		printf("merged: \n");
		for (i = 0; i < ls->backedge_count; i++)
			if (ls->backedge[i] != NULL)
				printf("Backedge: %i - %i, %i - %i\n",
					   ls->sorted[ls->backedge[i]->start],
					   ls->sorted[ls->backedge[i]->end],
					   ls->backedge[i]->start, ls->backedge[i]->end);
	}
#endif
	/* - remove backedge[] == NULL from array */

	for (j = ls->backedge_count - 1; ((j>=0) && (ls->backedge[j] == NULL));
		 j--);
	i=j;
	while (i >= 0) {
		if (ls->backedge[i] == NULL) { /* swap backedge[i] and backedge[j]*/
			n=ls->backedge[j];
			ls->backedge[j] = ls->backedge[i];
			ls->backedge[i] = n;
			i--;
			j--;
			ls->backedge_count--;
		} else i--;
	}
#ifdef LSRA_DEBUG_VERBOSE
	if (compileverbose) {
		printf("ready: \n");
		for (i=0; i < ls->backedge_count; i++)
			printf("Backedge: %i - %i, %i - %i\n",
				   ls->sorted[ls->backedge[i]->start],
				   ls->sorted[ls->backedge[i]->end],ls->backedge[i]->start,
				   ls->backedge[i]->end);
	}
#endif
}

void lsra_add_cfg(jitdata *jd, int from, int to) {
	struct _list *n;
	methodinfo *m;
	lsradata   *ls;

	m  = jd->m;
	ls = jd->ls;

	/* ignore Empty, Deleted,... Basic Blocks as target */
	/* TODO: Setup BasicBlock array before to avoid this */
	/*       best together with using the basicblock list, so lsra works */
	/*       with opt_loops, too */
	for (;(to < m->basicblockcount) && (m->basicblocks[to].flags < BBREACHED); to++);

	for (n=ls->succ[from]; (n!= NULL) && (n->value != to); n=n->next);
	if (n != NULL) return; /* edge from->to already existing */

	n=DNEW(struct _list);
			
	n->value=to;
	n->next=ls->succ[from];
	ls->succ[from]=n;

	n=DNEW(struct _list);
	n->value=from;
	n->next=ls->pred[to];
	ls->pred[to]=n;
	ls->num_pred[to]++;
}

/* add Edges from guarded Areas to Exception handlers in the CFG */ 	
void lsra_add_exceptions(jitdata *jd) {
	methodinfo  *m;
	lsradata    *ls; 
	int i;
	exceptiontable *ex;


	m  = jd->m;
	ls = jd->ls;

	ex = jd->exceptiontable;

	/* add cfg edges from all bb of a try block to the start of the according */
	/* exception handler to ensure the right order after depthfirst search    */

#ifdef LSRA_DEBUG_VERBOSE
	if (compileverbose)
		printf("ExTable(%i): ", jd->exceptiontablelength);
#endif

	for (; ex != NULL; ex = ex->down) {

#ifdef LSRA_DEBUG_VERBOSE
	if (compileverbose) {
		printf("[%i-%i]->%i ",ex->start->nr, ex->end->nr,
			   ex->handler->nr);
		if (ex->handler->nr >= m->basicblockcount) {
			log_text("Exceptionhandler Basicblocknummer invalid\n");
			abort();
		}
		if (m->basicblocks[ex->handler->nr].flags < BBREACHED) {
			log_text("Exceptionhandler Basicblocknummer not reachable\n");
			abort();
		}
		if (ex->start->nr > ex->end->nr) {
			log_text("Guarded Area starts after its end\n");
			abort();
		}
	}
#endif
		/* loop all valid Basic Blocks of the guarded area and add CFG edges  */
		/* to the appropriate handler */
		for (i=ex->start->nr; (i <= ex->end->nr) &&
				 (i < m->basicblockcount); i++)
			if (m->basicblocks[i].flags >= BBREACHED)
				lsra_add_cfg(jd, i, ex->handler->nr);
	}
#ifdef LSRA_DEBUG_VERBOSE
	if (compileverbose) {
		printf("\n");
	}
#endif
}

void lsra_add_jsr(jitdata *jd, int from, int to) {
	methodinfo *m;
	lsradata   *ls;
	struct _sbr *sbr, *n;
	struct _list *ret;

	ls = jd->ls;
	m  = jd->m;

	/* ignore Empty, Deleted,... Basic Blocks as target */
	/* TODO: Setup BasicBlock array before to avoid this */
	/*       best together with using the basicblock list, so lsra works */
	/*       with opt_loops, too */
	for (; (to < m->basicblockcount) && (m->basicblocks[to].flags < BBREACHED);
		 to++);
#ifdef LSRA_DEBUG_CHECK
		if (to == m->basicblockcount)
			{ log_text("Invalid subroutine start index\n"); assert(0); }
#endif

	lsra_add_cfg(jd, from, to);

	/* from + 1 ist the return Basic Block Index */
	for (from++; (from < m->basicblockcount) &&
			 (m->basicblocks[from].flags < BBREACHED); from++);
#ifdef LSRA_DEBUG_CHECK
	if (from == m->basicblockcount)
		{ log_text("Invalid return basic block index for jsr\n"); assert(0); }
#endif

	/* add subroutine info in ls->sbr.next */

	/* search for right place to insert */
	for (sbr = &(ls->sbr); (sbr->next != NULL) && (sbr->next->header < to); sbr=sbr->next);
	
	if ((sbr->next!= NULL) && (sbr->next->header == to)) {
		/* Entry for this sub already exist */
		sbr = sbr->next;
	} else {
		/* make new Entry and insert it in ls->sbr.next */
		n = DNEW( struct _sbr );
		n->header = to;
		n->ret = NULL;

		n->next = sbr->next;
		sbr->next = n;

		sbr = n;
	}

	/* now insert return adress in sbr->ret */
	ret = DNEW( struct _list);
	ret->value = from;
	ret->next = sbr->ret;
	sbr->ret = ret;
}

void lsra_add_sub( jitdata *jd, int b_index, struct _list *ret,
				   bool *visited )
{
	methodinfo *m;
	lsradata  *ls;
	struct _list *l;
	instruction *ip;
	bool next_block;

	m  = jd->m;
	ls = jd->ls;

	/* break at virtual End Block */
	if (b_index != m->basicblockcount) {
		visited[b_index] = true;
		next_block = false;

		if (m->basicblocks[b_index].flags < BBREACHED)
			next_block = true;
		if (!next_block && !(m->basicblocks[b_index].icount))
			next_block = true;

		if (!next_block) {
			ip = m->basicblocks[b_index].iinstr 
				+ m->basicblocks[b_index].icount -1;
		
			if (ip->opc == ICMD_JSR) /* nested Subroutines */
				next_block = true;
		}

		if (!next_block) {
			if (ip->opc == ICMD_RET) { 
				/* subroutine return found -> add return adresses to CFG */
				for (l = ret; l != NULL; l = l->next)
					lsra_add_cfg(jd, b_index, l->value);
			} else { /* follow CFG */
				for ( l = ls->succ[b_index]; l != NULL; l = l->next)
					if (!visited[l->value])
						lsra_add_sub(jd, l->value, ret, visited);
			}
		} else { /* fall through to next block */
				if (!visited[b_index + 1])
					lsra_add_sub(jd, b_index + 1, ret, visited);
		}
	}
}

/* Add subroutines from ls->sbr list to CFG */
void lsra_add_subs(jitdata *jd) {
	methodinfo *m;
	lsradata   *ls;
	struct _sbr *sbr;
	bool *visited;
	int i;
#ifdef LSRA_DEBUG_VERBOSE
	struct _list *ret;
#endif

	m  = jd->m;
	ls = jd->ls;

	visited = (bool *)DMNEW(int, m->basicblockcount + 1);
	for (i=0; i <= m->basicblockcount; i++) visited[i] = false;
	for (sbr = ls->sbr.next; sbr != NULL; sbr=sbr->next) {

#ifdef LSRA_DEBUG_VERBOSE
		if (compileverbose) {
			printf("Subroutine Header: %3i Return Adresses:",sbr->header);
			for (ret = sbr->ret; ret != NULL; ret = ret->next)
				printf(" %3i", ret->value);
			printf("\n");
		}
#endif
		lsra_add_sub(jd, sbr->header, sbr->ret, visited );
	}
}

/* Generate the Control Flow Graph             */
/* ( pred,succ,num_pred of lsradata structure) */

void lsra_make_cfg(jitdata *jd) {
	methodinfo *m;
	lsradata *ls;
	instruction *ip;
	s4 *s4ptr;
	int high, low, count;
	int b_index, len;

	m  = jd->m;
	ls = jd->ls;

	b_index=0;
	while (b_index < m->basicblockcount ) {
		if ((m->basicblocks[b_index].flags >= BBREACHED) &&
			(len = m->basicblocks[b_index].icount)) {
			/* block is valid and contains instructions	*/

			/* set ip to last instruction	*/
			ip = m->basicblocks[b_index].iinstr +
				m->basicblocks[b_index].icount -1;
			while ((len>0) && (ip->opc == ICMD_NOP)) {
				len--;
				ip--;
			}
			switch (ip->opc) {			/* check type of last instruction */
			    case ICMD_RETURN:
			    case ICMD_IRETURN:
			    case ICMD_LRETURN:
				case ICMD_FRETURN:
				case ICMD_DRETURN:
				case ICMD_ARETURN:
				case ICMD_ATHROW:
					lsra_add_cfg(jd, b_index, m->basicblockcount);
					break;				  /* function returns -> end of graph */

				case ICMD_IFNULL:
				case ICMD_IFNONNULL:
				case ICMD_IFEQ:
				case ICMD_IFNE:
				case ICMD_IFLT:
				case ICMD_IFGE:
				case ICMD_IFGT:
				case ICMD_IFLE:
				case ICMD_IF_LEQ:
				case ICMD_IF_LNE:
				case ICMD_IF_LLT:
				case ICMD_IF_LGE:
				case ICMD_IF_LGT:
				case ICMD_IF_LLE:
				case ICMD_IF_ICMPEQ:
				case ICMD_IF_ICMPNE:
				case ICMD_IF_ICMPLT:
				case ICMD_IF_ICMPGE:
				case ICMD_IF_ICMPGT:
				case ICMD_IF_ICMPLE:
				case ICMD_IF_LCMPEQ:
				case ICMD_IF_LCMPNE:
				case ICMD_IF_LCMPLT:
				case ICMD_IF_LCMPGE:
				case ICMD_IF_LCMPGT:
				case ICMD_IF_LCMPLE:
				case ICMD_IF_ACMPEQ:
				case ICMD_IF_ACMPNE:		    /* branch -> add next block */
					lsra_add_cfg(jd, b_index, b_index+1);
					/* fall throu -> add branch target */
			   
				case ICMD_GOTO:
					lsra_add_cfg(jd, b_index,  m->basicblockindex[ip->op1]);
					break;					/* visit branch (goto) target	*/
				
				case ICMD_TABLESWITCH:		/* switch statement				*/
					s4ptr = ip->val.a;
				
					lsra_add_cfg(jd, b_index,  m->basicblockindex[*s4ptr]);
				
					s4ptr++;
					low = *s4ptr;
					s4ptr++;
					high = *s4ptr;
				
					count = (high-low+1);
				
					while (--count >= 0) {
						s4ptr++;
						lsra_add_cfg(jd, b_index, 
									 m->basicblockindex[*s4ptr]);
				    }
					break;
				
				case ICMD_LOOKUPSWITCH:		/* switch statement				*/
					s4ptr = ip->val.a;
			   
					lsra_add_cfg(jd, b_index,  m->basicblockindex[*s4ptr]);
				
					++s4ptr;
					count = *s4ptr++;
				
					while (--count >= 0) {
						lsra_add_cfg(jd, b_index, 
									 m->basicblockindex[s4ptr[1]]);
						s4ptr += 2;
				    }
					break;

				case ICMD_JSR:
					lsra_add_jsr(jd, b_index, m->basicblockindex[ip->op1]);
					break;
				
				case ICMD_RET:
					break;
				
				default:
					lsra_add_cfg(jd, b_index, b_index + 1 );
					break;	
			} /* switch (ip->opc)*/                        
		}     /* if ((m->basicblocks[blockIndex].icount)&& */
		      /*     (m->basicblocks[b_index].flags >= BBREACHED)) */
		b_index++;
	}             /* while (b_index < m->basicblockcount ) */
}

void lsra_init(jitdata *jd) {
	methodinfo   *m;
	lsradata     *ls; 
	int i;

	ls = jd->ls;
	m  = jd->m;

	/* Init LSRA Data Structures */
	/* allocate lifetimes for all Basicblocks */
	/* + 1 for an artificial exit node */
	/* which is needed as "start" point for the reverse postorder sorting */
	ls->pred = DMNEW(struct _list *, m->basicblockcount+1);
	ls->succ = DMNEW(struct _list *, m->basicblockcount+1);
	ls->sorted = DMNEW(int , m->basicblockcount+1);
	ls->sorted_rev = DMNEW(int , m->basicblockcount+1); 
	ls->num_pred = DMNEW(int , m->basicblockcount+1);
	ls->nesting = DMNEW(long , m->basicblockcount+1); 
	for (i=0; i<m->basicblockcount; i++) {
		ls->pred[i]=NULL;
		ls->succ[i]=NULL;
		ls->sorted[i]=-1;
		ls->sorted_rev[i]=-1;
		ls->num_pred[i]=0;
		ls->nesting[i] = 1;
	}
	ls->pred[m->basicblockcount]=NULL;
	ls->succ[m->basicblockcount]=NULL;
	ls->sorted[m->basicblockcount]=-1;
	ls->sorted_rev[m->basicblockcount]=-1;
	ls->num_pred[m->basicblockcount]=0;	

	ls->sbr.next = NULL;

	ls->v_index = -1;
}

void lsra_setup(jitdata *jd) {
	methodinfo *m;
	codegendata *cd;
	lsradata *ls;

#ifdef LSRA_DEBUG_VERBOSE
	basicblock  *bptr;
	struct _list *nl;
#endif

	int i;

#if !defined(LV)
	registerdata *rd;

	rd = jd->rd;
#endif

	ls = jd->ls;
	m  = jd->m;
	cd = jd->cd;

#if defined(ENABLE_LOOP)
	/* Loop optimization "destroys" the basicblock array */
	/* TODO: work with the basicblock list               */
	if (opt_loops) {
		log_text("lsra not possible with loop optimization\n");
		abort();
	}
#endif /* defined(ENABLE_LOOP) */

	/* Setup LSRA Data structures */

	/* Generate the Control Flow Graph */
	lsra_make_cfg(jd);
	/* gather nesting before adding of Exceptions and Subroutines!!! */

#ifdef USAGE_COUNT
	lsra_DFS(jd);  
	lsra_get_nesting(jd);
#endif

#ifdef LSRA_DEBUG_VERBOSE
	if (compileverbose) {
	printf("Successors:\n");
	for (i=0; i < m->basicblockcount; i++) {
		printf("%3i->: ",i);
		for (nl=ls->succ[i]; nl!= NULL; nl=nl->next)
			printf("%3i ",nl->value);
		printf("\n");
	}
	printf("Predecessors:\n");
	for (i=0; i < m->basicblockcount; i++) {
		printf("%3i->: ",i);
		for (nl=ls->pred[i]; nl!= NULL; nl=nl->next)
			printf("%3i ",nl->value);
		printf("\n");
	}
	printf("Sorted: ");
	for (i=0; i < m->basicblockcount; i++) printf("%3i ", ls->sorted[i]);
	printf("\n");
	printf("Sorted_rev: ");
	for (i=0; i < m->basicblockcount; i++) printf("%3i ", ls->sorted_rev[i]);
	printf("\n");
	}
#endif

	/* add subroutines before exceptions! They "destroy" the CFG */
	lsra_add_subs(jd); 
 	lsra_add_exceptions(jd);

	/* generate reverse post order sort */
	lsra_DFS(jd);  

	/* setup backedge and nested data structures*/
	lsra_get_backedges(jd);

	liveness_init(jd);

	ls->lifetimecount = ls->maxlifetimes + jd->maxlocals * (TYPE_ADR+1);
	ls->lifetime = DMNEW(struct lifetime, ls->lifetimecount);
	ls->lt_used  = DMNEW(int, ls->lifetimecount);
	ls->lt_int   = DMNEW(int, ls->lifetimecount);
	ls->lt_int_count = 0;
	ls->lt_flt   = DMNEW(int, ls->lifetimecount);
	ls->lt_flt_count = 0;
	ls->lt_mem   = DMNEW(int, ls->lifetimecount);
	ls->lt_mem_count = 0;

	for (i=0; i < ls->lifetimecount; i++) ls->lifetime[i].type = -1;

#ifdef LSRA_DEBUG_VERBOSE
	if (compileverbose) {
	printf("Successors:\n");
	for (i=0; i < m->basicblockcount; i++) {
		printf("%3i->: ",i);
		for (nl=ls->succ[i]; nl!= NULL; nl=nl->next)
			printf("%3i ",nl->value);
		printf("\n");
	}
	printf("Predecessors:\n");
	for (i=0; i < m->basicblockcount; i++) {
		printf("%3i->: ",i);
		for (nl=ls->pred[i]; nl!= NULL; nl=nl->next)
			printf("%3i ",nl->value);
		printf("\n");
	}
	printf("Sorted: ");
	for (i=0; i < m->basicblockcount; i++) printf("%3i ", ls->sorted[i]);
	printf("\n");
	printf("Sorted_rev: ");
	for (i=0; i < m->basicblockcount; i++) printf("%3i ", ls->sorted_rev[i]);
	printf("\n");
	}
#endif


#ifdef LSRA_DEBUG_CHECK
	/* compare m->basicblocks[] with the list basicblocks->next */
	i=0;
	bptr = m->basicblocks;
	while (bptr != NULL) {
		if (i > m->basicblockcount){
			{ log_text("linked bb list does not correspond with bb array(1)\n");
				assert(0); }
		}
		if (bptr != &(m->basicblocks[i])){
			{ log_text("linked bb list does not correspond with bb array(2)\n");
				assert(0); }
		}

		i++;
		bptr=bptr->next;
	}
	if (i<m->basicblockcount){
		{ log_text("linked bb list does not correspond with bb array(3)\n");
			assert(0); }
	}

#endif

	liveness_setup(jd);

#if defined(LV)
	liveness(jd);
#else /* LV */
	{
		int p, t;
		methoddesc *md = m->parseddesc;

		/* Create Stack Slot lifetimes over all basic blocks */
		for (i=m->basicblockcount-1; i >= 0; i--) {
			if (ls->sorted[i] != -1) {
				lsra_scan_registers_canditates(jd, ls->sorted[i]);
				lsra_join_lifetimes(jd, ls->sorted[i]);
			}
		}

		/* Parameter initialisiation for locals [0 .. paramcount[            */
		/* -> add local var write access at (bb=0,iindex=-1)                 */
		/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!   */
		/* this needs a special treatment, wenn lifetimes get extended       */
		/* over backedges, since this parameter initialisation happens       */
		/* outside of Basic Block 0 !!!!                                     */
		/* this could have been avoided by marking the read access with -1,0 */

		for (p = 0, i = 0; p < md->paramcount; p++) {
			t = md->paramtypes[p].type;

			if (rd->locals[i][t].type >= 0)	
				/* Param to Local init happens before normal Code */
				lsra_usage_local(ls, i, t, 0, -1, LSRA_STORE); 
			i++;
			/* increment local counter a second time  */
			/* for 2 word types */
			if (IS_2_WORD_TYPE(t))
				i++;                 
		}  /* end for */
	}
#endif /* LV */

	lsra_calc_lifetime_length(jd);

#ifdef LSRA_DEBUG_VERBOSE
	if (compileverbose)
		printf("Basicblockcount: %4i\n",m->basicblockcount);
#endif
}


void lsra_reg_setup(jitdata *jd, struct lsra_register *int_reg,
					struct lsra_register *flt_reg ) {
	int i, j, iarg, farg;
	int int_sav_top;
	int flt_sav_top;
	bool *fltarg_used, *intarg_used;
	methoddesc *md;
	methodinfo *m;
	registerdata *rd;

	m  = jd->m;
	rd = jd->rd;
	md = m->parseddesc;

	int_reg->nregdesc = nregdescint;
	flt_reg->nregdesc = nregdescfloat;
	if (code_is_leafmethod(code)) { 
		/* Temp and Argumentregister can be used as saved registers */

		int_reg->sav_top = INT_ARG_CNT + INT_TMP_CNT + INT_SAV_CNT;
		int_reg->sav_reg = DMNEW(int, int_reg->sav_top);
		int_reg->tmp_reg = NULL;
		int_reg->tmp_top = -1;
		flt_reg->sav_top = FLT_ARG_CNT + FLT_TMP_CNT + FLT_SAV_CNT;
		flt_reg->sav_reg = DMNEW(int, flt_reg->sav_top);
		flt_reg->tmp_reg = NULL;
		flt_reg->tmp_top = -1;

		/* additionaly precolour registers for Local Variables acting as */
		/* Parameters */

		farg = FLT_ARG_CNT;
		iarg = INT_ARG_CNT;

		intarg_used = DMNEW(bool, INT_ARG_CNT);
		for (i=0; i < INT_ARG_CNT; i++)
			intarg_used[i]=false;

		fltarg_used = DMNEW(bool, FLT_ARG_CNT);
		for (i=0; i < FLT_ARG_CNT; i++)
			fltarg_used[i]=false;

		int_sav_top=int_reg->sav_top;
		flt_sav_top=flt_reg->sav_top;

		for (i=0; (i < md->paramcount); i++) {
			if (!md->params[i].inmemory) {
				if (IS_INT_LNG_TYPE(md->paramtypes[i].type)) {
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
					if (IS_2_WORD_TYPE(md->paramtypes[i].type)) {
						int_reg->sav_reg[--int_sav_top] = 
							rd->argintregs[GET_HIGH_REG(md->params[i].regoff)];
						intarg_used[GET_HIGH_REG(md->params[i].regoff)]=true;
						/*used -> don't copy later on */
						int_reg->sav_reg[--int_sav_top] = 
							rd->argintregs[GET_LOW_REG(md->params[i].regoff)];
						intarg_used[GET_LOW_REG(md->params[i].regoff)]=true;
						/*used -> don't copy later on */
					} else
#endif
					{ /* !IS_2_WORD_TYPE(md->paramtypes[i].type */
						int_reg->sav_reg[--int_sav_top] = 
							rd->argintregs[md->params[i].regoff];
						intarg_used[md->params[i].regoff]=true;
						/*used -> don't copy later on */
					}
				}
#if !defined(SUPPORT_PASS_FLOATARGS_IN_INTREGS)
				/* do not precolour float arguments if they are passed in     */
				/* integer registers. But these integer argument registers    */
				/* still be used in the method! */
				else { /* IS_FLT_DBL_TYPE(md->paramtypes[i].type */
						flt_reg->sav_reg[--flt_sav_top] = 
							rd->argfltregs[md->params[i].regoff];
						fltarg_used[md->params[i].regoff]=true;
				}
#endif
					
			}
		}

		/* copy rest of argument registers to flt_reg->sav_reg and */
		/* int_reg->sav_reg; */
		for (i=0; i < INT_ARG_CNT; i++)
			if (!intarg_used[i])
				int_reg->sav_reg[--int_sav_top]=rd->argintregs[i];
		for (i=0; i < FLT_ARG_CNT; i++)
			if (!fltarg_used[i])
				flt_reg->sav_reg[--flt_sav_top]=rd->argfltregs[i];

		/* copy temp registers to flt_reg->sav_reg and int_reg->sav_reg */
		for (i=0; i < INT_TMP_CNT; i++)
			int_reg->sav_reg[--int_sav_top]=rd->tmpintregs[i];
		for (i=0; i < FLT_TMP_CNT; i++)
			flt_reg->sav_reg[--flt_sav_top]=rd->tmpfltregs[i];

	} else {
		/* non leaf method -> use Argument Registers [arg[int|flt]reguse */
		/* ... [INT|FLT]_ARG_CNT[ as temp reg */
		/* divide temp and saved registers */
		int argintreguse, argfltreguse;
#ifdef LV
		/* with Locals as non SAVEDVAR, the used arg[int|flt] as in params */
		/* of the method itself have to be regarded, or mismatch before    */
		/* block 0 with parameter copy could happen! */
		argintreguse = max(rd->argintreguse, md->argintreguse);
		argfltreguse = max(rd->argfltreguse, md->argfltreguse);
#else
		argintreguse = rd->argintreguse;
		argfltreguse = rd->argfltreguse;
#endif
		int_sav_top = int_reg->sav_top = INT_SAV_CNT;
		int_reg->sav_reg = DMNEW(int, int_reg->sav_top);
		int_reg->tmp_top = INT_TMP_CNT +
			max(0, (INT_ARG_CNT - argintreguse));
		int_reg->tmp_reg = DMNEW(int, int_reg->tmp_top);

		flt_sav_top =flt_reg->sav_top = FLT_SAV_CNT;
		flt_reg->sav_reg = DMNEW(int, flt_reg->sav_top);
		flt_reg->tmp_top = FLT_TMP_CNT +
			max(0 , (FLT_ARG_CNT - argfltreguse));
		flt_reg->tmp_reg = DMNEW(int, flt_reg->tmp_top);

		/* copy temp and unused argument registers to flt_reg->tmp_reg and */
		/* int_reg->tmp_reg */
		for (i=0; i < INT_TMP_CNT; i++)
			int_reg->tmp_reg[i]=rd->tmpintregs[i];
		for (j=argintreguse; j < INT_ARG_CNT; j++, i++)
			int_reg->tmp_reg[i]=rd->argintregs[j];
		for (i=0; i < FLT_TMP_CNT; i++)
			flt_reg->tmp_reg[i]=rd->tmpfltregs[i];
		for (j=argfltreguse; j < FLT_ARG_CNT; j++, i++)
			flt_reg->tmp_reg[i]=rd->argfltregs[j];
	}

	/* now copy saved registers to flt_reg->sav_reg and int_reg->sav_reg */
	for (i = INT_SAV_CNT-1; i >= 0; i--)
		int_reg->sav_reg[--int_sav_top]=rd->savintregs[i];
	for (i = FLT_SAV_CNT-1; i >= 0; i--)
		flt_reg->sav_reg[--flt_sav_top]=rd->savfltregs[i];
	/* done */
}

void lsra_insertion_sort( struct lsradata *ls, int *a, int lo, int hi) {
	int i,j,t,tmp;

	for (i=lo+1; i<=hi; i++) {
		j=i;
		t=ls->lifetime[a[j]].i_start;
		tmp = a[j];
		while ((j>lo) && (ls->lifetime[a[j-1]].i_start > t)) {
			a[j]=a[j-1];
			j--;
		}
		a[j]=tmp;
	}
}

void lsra_qsort( struct lsradata *ls, int *a, int lo, int hi) {
	int i,j,x,tmp;
	if (lo < hi) {
		if ( (lo+5)<hi) {
			i = lo;
			j = hi;
			x = ls->lifetime[a[(lo+hi)/2]].i_start;

			while (i <= j) {
				while (ls->lifetime[a[i]].i_start < x) i++;
				while (ls->lifetime[a[j]].i_start > x) j--;
				if (i <= j) {
					/* exchange a[i], a[j] */
					tmp = a[i];
					a[i] = a[j];
					a[j] = tmp;
			
					i++;
					j--;
				}
			}

			if (lo < j) lsra_qsort( ls, a, lo, j);
			if (i < hi) lsra_qsort( ls, a, i, hi);
		} else
			lsra_insertion_sort(ls, a, lo, hi);
	}
}

void lsra_param_sort(struct lsradata *ls, int *lifetime, int lifetime_count) {

	int param_count;
	int i,j,tmp;

	/* count number of parameters ( .i_start == -1) */
	for (param_count=0; (param_count < lifetime_count) &&
		 (ls->lifetime[lifetime[param_count]].i_start == -1); param_count++);

	if (param_count > 0) {
		/* now sort the parameters by v_index */
		for (i=0; i < param_count -1; i++)
			for (j=i+1; j < param_count; j++)
				if ( ls->lifetime[lifetime[i]].v_index >
					 ls->lifetime[lifetime[j]].v_index) {
					/* swap */
					tmp = lifetime[i];
					lifetime[i]=lifetime[j];
					lifetime[j]=tmp;
				}
	}			
}

void lsra_main(jitdata *jd) {
#ifdef LSRA_DEBUG_VERBOSE
	int i;
#endif
	int lsra_mem_use;
	int lsra_reg_use;
	struct lsra_register flt_reg, int_reg;
	lsradata *ls;
	registerdata *rd;
#if defined(__I386__)
	methodinfo *m;

	m  = jd->m;
#endif
	ls = jd->ls;
	rd = jd->rd;

/* sort lifetimes by increasing start */
	lsra_qsort( ls, ls->lt_mem, 0, ls->lt_mem_count - 1);
	lsra_qsort( ls, ls->lt_int, 0, ls->lt_int_count - 1);
	lsra_qsort( ls, ls->lt_flt, 0, ls->lt_flt_count - 1);
/* sort local vars used as parameter */
	lsra_param_sort( ls, ls->lt_int, ls->lt_int_count);
	lsra_param_sort( ls, ls->lt_flt, ls->lt_flt_count);
	lsra_reg_setup(jd, &int_reg, &flt_reg);

#ifdef LSRA_DEBUG_VERBOSE
	if (compileverbose) {
		printf("INTSAV REG: ");
		for (i=0; i<int_reg.sav_top; i++)
			printf("%2i ",int_reg.sav_reg[i]);
		printf("\nINTTMP REG: ");
		for (i=0; i<int_reg.tmp_top; i++)
			printf("%2i ",int_reg.tmp_reg[i]);
		printf("\nFLTSAV REG: ");
		for (i=0; i<flt_reg.sav_top; i++)
			printf("%2i ",flt_reg.sav_reg[i]);
		printf("\nFLTTMP REG: ");
		for (i=0; i<flt_reg.tmp_top; i++)
			printf("%2i ",flt_reg.tmp_reg[i]);
		printf("\n");
	}
#endif
	ls->active_tmp = DMNEW( struct lifetime *, max(INT_REG_CNT, FLT_REG_CNT));
	ls->active_sav = DMNEW( struct lifetime *, max(INT_REG_CNT, FLT_REG_CNT));

	lsra_reg_use=INT_SAV_CNT; /* init to no saved reg used... */
	_lsra_main(jd, ls->lt_int, ls->lt_int_count, &int_reg, &lsra_reg_use);
	if (lsra_reg_use > INT_SAV_CNT)
		lsra_reg_use=INT_SAV_CNT;
	rd->savintreguse = lsra_reg_use;

	lsra_reg_use = FLT_SAV_CNT; /* no saved reg used... */
	_lsra_main(jd, ls->lt_flt, ls->lt_flt_count, &flt_reg, &lsra_reg_use);
	if (lsra_reg_use > FLT_SAV_CNT)
		lsra_reg_use=FLT_SAV_CNT;
	rd->savfltreguse=lsra_reg_use;

	/* rd->memuse was already set in stack.c to allocate stack space for */
	/* passing arguments to called methods */
#if defined(__I386__)
	if (checksync && code_is_synchronized(code)) {
		/* reserve 0(%esp) for Monitorenter/exit Argument on i386 */
		if (rd->memuse < 1)
			rd->memuse = 1;
	}
#endif

	lsra_mem_use = rd->memuse; /* Init with memuse from stack.c */

	lsra_alloc(jd, ls->lt_mem, ls->lt_mem_count, &lsra_mem_use);
	lsra_alloc(jd, ls->lt_int, ls->lt_int_count, &lsra_mem_use);
	lsra_alloc(jd, ls->lt_flt, ls->lt_flt_count, &lsra_mem_use);

	rd->memuse=lsra_mem_use;

#ifdef LSRA_DEBUG_VERBOSE
	if (compileverbose) {
		printf("Int RA complete \n");
		printf("Lifetimes after splitting int: \n");
		print_lifetimes(jd, ls->lt_int, ls->lt_int_count);
		
		printf("Flt RA complete \n");
		printf("Lifetimes after splitting flt:\n");
		print_lifetimes(jd, ls->lt_flt, ls->lt_flt_count);
		
		printf("Rest RA complete \n");
		printf("Lifetimes after leftt:\n");
		print_lifetimes(jd, ls->lt_mem, ls->lt_mem_count);
	}
#endif
}

void lsra_alloc(jitdata *jd, int *lifet, int lifetimecount, int *mem_use)
{
	int flags,regoff;
	struct lifetime *lt;
	struct freemem *fmem;
	struct stackslot *n;
	int lt_index;
#ifdef HAS_4BYTE_STACKSLOT
	struct freemem *fmem_2;
#endif
	registerdata *rd;
	lsradata     *ls;

	rd = jd->rd;
	ls = jd->ls;

	fmem = DNEW(struct freemem);
	fmem->off  = -1;
	fmem->next = NULL;
#ifdef HAS_4BYTE_STACKSLOT
	fmem_2=DNEW(struct freemem);
	fmem_2->off  = -1;
	fmem_2->next = NULL;
#endif

	for (lt_index = 0; lt_index < lifetimecount; lt_index ++) {
		lt = &(ls->lifetime[lifet[lt_index]]);
#ifdef LSRA_MEMORY
		lt->reg = -1;
#endif
		if (lt->reg == -1) {
			flags = INMEMORY;
#ifdef HAS_4BYTE_STACKSLOT
			if (IS_2_WORD_TYPE(lt->type))
				regoff = lsra_getmem(lt, fmem_2, mem_use);
			else
#endif
			regoff = lsra_getmem(lt, fmem, mem_use);
		} else {
			flags  = lt->savedvar;
			regoff = lt->reg;
		}

		if (lt->v_index < 0) {
			for (n = lt->local_ss; n != NULL; n = n->next) {
				lsra_setflags(&(n->s->flags), flags);
				n->s->regoff = regoff;
			}
		} else { /* local var */
			if (rd->locals[lt->v_index][lt->type].type >= 0) {
				rd->locals[lt->v_index][lt->type].flags  = flags;
				rd->locals[lt->v_index][lt->type].regoff = regoff;
			} else { 
				log_text("Type Data mismatch\n");
				abort();
			}
		}		
		lt->reg = regoff;
	}
}

void lsra_setflags(int *flags, int newflags)
{
	if ( newflags & INMEMORY)
		*flags |= INMEMORY;
	else
		*flags &= ~INMEMORY;
	
	if (newflags & SAVEDVAR)
		*flags |= SAVEDVAR;
}

int lsra_getmem(struct lifetime *lt, struct freemem *fmem, int *mem_use)
{
	struct freemem *fm, *p;

	/* no Memory Slot allocated till now or all are still live */
	if ((fmem->next == NULL) || (fmem->next->end > lt->i_start)) {
#ifdef HAS_4BYTE_STACKSLOT
		if (IS_2_WORD_TYPE(lt->type))
			if ( (*mem_use)&1 ) /* align memory location for 2 Word Types */
				(*mem_use)++;
		fm=lsra_getnewmem(mem_use);
		if (IS_2_WORD_TYPE(lt->type))
			/* allocate a second following Slot for 2 Word Types */
			(*mem_use)++;
#else
		fm=lsra_getnewmem(mem_use);
#endif
	} else {
		/* Memoryslot free */
		fm = fmem->next;
		fmem->next = fm->next;
		fm->next = NULL;
	}
	fm->end = lt->i_end;
	for (p = fmem; (p->next != NULL) && (p->next->end < fm->end); p = p->next);
	fm->next = p->next;
	p->next = fm;
	return fm->off;
}

struct freemem *lsra_getnewmem(int *mem_use)
{
	struct freemem *fm;

	fm = DNEW(struct freemem);
	fm->next = NULL;
	fm->off = *mem_use;
	(*mem_use)++;
	return fm;
}

void _lsra_main(jitdata *jd, int *lifet, int lifetimecount,
				struct lsra_register *reg, int *reg_use)
{
	struct lifetime *lt;
	int lt_index;
	int reg_index;
	int regsneeded;
	bool temp; /* reg from temp registers (true) or saved registers (false) */
	methodinfo *m;
	lsradata *ls;

	m  = jd->m;
	ls = jd->ls;
	
#if !defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
	regsneeded = 0;
#endif
	if ((reg->tmp_top+reg->sav_top) == 0) {

		/* no registers available */
		for (lt_index = 0; lt_index < lifetimecount; lt_index++)
			ls->lifetime[lifet[lt_index]].reg = -1;
		return;
	}

	ls->active_tmp_top = 0;
	ls->active_sav_top = 0;

	for (lt_index = 0; lt_index < lifetimecount; lt_index++) {
		lt = &(ls->lifetime[lifet[lt_index]]);

#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
	regsneeded = (lt->type == TYPE_LNG)?1:0;
#endif

		lsra_expire_old_intervalls(jd, lt, reg);
		reg_index = -1;
		temp = false;
		if (lt->savedvar || code_is_leafmethod(code)) {
			/* use Saved Reg (in case of leafmethod all regs are saved regs) */
			if (reg->sav_top > regsneeded) {
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
				if (regsneeded)
					reg_index = PACK_REGS(reg->sav_reg[--reg->sav_top],
										  reg->sav_reg[--reg->sav_top]);
				else
#endif

					reg_index = reg->sav_reg[--reg->sav_top];
			}
		} else { /* use Temp Reg or if none is free a Saved Reg */
			if (reg->tmp_top > regsneeded) {
				temp = true;
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
			if (regsneeded)
				reg_index = PACK_REGS(reg->tmp_reg[--reg->tmp_top],
									  reg->tmp_reg[--reg->tmp_top]);
			else
#endif
				reg_index = reg->tmp_reg[--reg->tmp_top];
			}
			else
				if (reg->sav_top > regsneeded) {

#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
				if (regsneeded)
					reg_index = PACK_REGS(reg->sav_reg[--reg->sav_top],
										  reg->sav_reg[--reg->sav_top]);
				else
#endif
					reg_index = reg->sav_reg[--reg->sav_top];
				}
		}
		if (reg_index == -1) /* no reg is available anymore... -> spill */
			spill_at_intervall(jd, lt);
		else {
			lt->reg = reg_index;
			if (temp)
				lsra_add_active(lt, ls->active_tmp, &(ls->active_tmp_top));
			else {
				if (reg->sav_top<*reg_use) *reg_use=reg->sav_top;
				lsra_add_active(lt, ls->active_sav, &(ls->active_sav_top));
			}
		}
	}
}

void lsra_add_active(struct lifetime *lt, struct lifetime **active,
					 int *active_top)
{
	int i, j;

	for(i = 0; (i < *active_top) && (active[i]->i_end < lt->i_end); i++);
	for(j = *active_top; j > i; j--) active[j] = active[j-1];
	(*active_top)++;
	active[i] = lt;
}

void lsra_expire_old_intervalls(jitdata *jd, struct lifetime *lt,
								struct lsra_register *reg)
{
	_lsra_expire_old_intervalls(jd, lt, reg, jd->ls->active_tmp, 
								&(jd->ls->active_tmp_top));
	_lsra_expire_old_intervalls(jd, lt, reg, jd->ls->active_sav, 
								&(jd->ls->active_sav_top));
}

void _lsra_expire_old_intervalls(jitdata *jd, struct lifetime *lt,
								 struct lsra_register *reg,
								 struct lifetime **active, int *active_top)
{
	int i, j, k;

	for(i = 0; i < *active_top; i++) {
		if (active[i]->i_end > lt->i_start) break;

		/* make active[i]->reg available again */
		if (code_is_leafmethod(code)) { 
			/* leafmethod -> don't care about type -> put all again into */
			/* reg->sav_reg */
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
			if (active[i]->type == TYPE_LNG) {
				reg->sav_reg[reg->sav_top++] = GET_LOW_REG(active[i]->reg);
				reg->sav_reg[reg->sav_top++] = GET_HIGH_REG(active[i]->reg);
			} else
#endif
				reg->sav_reg[reg->sav_top++] = active[i]->reg;
		} else { 
			/* no leafmethod -> distinguish between temp and saved register */
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
			if (active[i]->type == TYPE_LNG) {
				/* no temp and saved regs are packed together, so looking at */
				/* LOW_REG is sufficient */
				if ( reg->nregdesc[ GET_LOW_REG(active[i]->reg)] == REG_SAV) {
					reg->sav_reg[reg->sav_top++] = GET_LOW_REG(active[i]->reg);
					reg->sav_reg[reg->sav_top++] = GET_HIGH_REG(active[i]->reg);
				} else {
					reg->tmp_reg[reg->tmp_top++] = GET_LOW_REG(active[i]->reg);
					reg->tmp_reg[reg->tmp_top++] = GET_HIGH_REG(active[i]->reg);
				}
			} else
#endif
			if ( reg->nregdesc[active[i]->reg] == REG_SAV) {
					reg->sav_reg[reg->sav_top++] = active[i]->reg;
			} else {
					reg->tmp_reg[reg->tmp_top++] = active[i]->reg;
			}
		}
	}
	
	/* active[0..i[ is to be removed */
	/* -> move [i..*active_top[ to [0..*active_top-i[ */
	for(k = 0, j = i; (j < *active_top); k++,j++)
		active[k] = active[j];

	(*active_top) -= i;

}

void spill_at_intervall(jitdata *jd, struct lifetime *lt )
{
	if (lt->savedvar || code_is_leafmethod(code)) {
		_spill_at_intervall(lt, jd->ls->active_sav, &(jd->ls->active_sav_top));
	} else {
		_spill_at_intervall(lt, jd->ls->active_tmp, &(jd->ls->active_tmp_top));
		if (lt->reg == -1) { /* no tmp free anymore */
			_spill_at_intervall(lt, jd->ls->active_sav, 
								&(jd->ls->active_sav_top));
		}
	}
}

void _spill_at_intervall(struct lifetime *lt, struct lifetime **active,
						 int *active_top)
{
	int i, j;
#ifdef USAGE_COUNT_EXACT
	int u_min, i_min;
#endif

	if (*active_top == 0) {
		lt->reg=-1;
		return;
	}
	
	i = *active_top - 1;
#if defined(USAGE_COUNT_EXACT)
	/* find intervall which ends later or equal than than lt and has the lowest
	   usagecount lower than lt */
	i_min = -1;
	u_min = lt->usagecount;
	for (; (i >= 0) && (active[i]->i_end >= lt->i_end); i--) {
		if (active[i]->usagecount < u_min) {
			u_min = active[i]->usagecount;
			i_min = i;
		}
	}

	if (i_min != -1) {
		i = i_min;
#else
# if defined(USAGE_COUNT) && !defined(USAGE_COUNT_EXACT)
	if ((active[i]->i_end >= lt->i_end) 
		 && (active[i]->usagecount < lt->usagecount)) {
# else /* "normal" LSRA heuristic */
	/* get last intervall from active */
	if (active[i]->i_end > lt->i_end) {
# endif
#endif
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
		/* Don't spill between one and two word int types */
		if ((active[i]->type == TYPE_LNG) != (lt->type == TYPE_LNG))
			return;
#endif
		lt->reg = active[i]->reg;
		active[i]->reg=-1;
		
		(*active_top)--;
		for (j = i; j < *active_top; j++)
			active[j] = active[j + 1];

		lsra_add_active(lt, active, active_top);
	} else {
		lt->reg=-1;
	}
}

void lsra_calc_lifetime_length(jitdata *jd) {
	methodinfo *m;
	lsradata *ls;
	codegendata *cd;
	struct lifetime *lt;
#if defined(LSRA_DEBUG_VERBOSE) || !defined(LV)
 	int i;
#endif
	int lt_index;
	int lifetimecount;
	int flags; /* 0 INMEMORY -> ls->lt_mem */
	           /* 1 INTREG   -> ls->lt_int  */
	           /* 2 FLTREG   -> ls->lt_flt  */


	m  = jd->m;
	ls = jd->ls;
	cd = jd->cd;

#ifdef LSRA_DEBUG_VERBOSE
	if (compileverbose) {
	printf("icount_block: ");
	for (i=0; i < m->basicblockcount; i++)
	    printf("(%3i-%3i) ",i, ls->icount_block[i]);
	printf("\n");
	}
#endif

	/* extend lifetime over backedges (for the lsra version without exact
	   liveness analysis)
	   now iterate through lifetimes and expand them */
	
	lifetimecount = 0;
	for(lt_index = 0 ;lt_index < ls->lifetimecount; lt_index++) {
		if ( ls->lifetime[lt_index].type != -1) { /* used lifetime */
			/* remember lt_index in lt_sorted */
			ls->lt_used[lifetimecount++] = lt_index; 
			lt = &(ls->lifetime[lt_index]);
#if defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
			/* prevent conflicts between lifetimes of type long by increasing 
			   the lifetime by one instruction 
			   i.e.(ri/rj)  ...       
			       (rk/rl)  ICMD_LNEG 
			   with i==l and/or j==k  
			   to resolve this during codegeneration a temporary register     
			   would be needed */
			if (lt->type == TYPE_LNG) 
				lt->i_last_use++;
#endif

/* distribute lifetimes to lt_int, lt_flt and lt_mem */

			lt->reg = -1;

			switch (lt->type) {
			case TYPE_LNG:
#if defined(HAS_4BYTE_STACKSLOT) && !defined(SUPPORT_COMBINE_INTEGER_REGISTERS)
				flags = 0;
#else
				flags = 1;
#endif
				break;

			case TYPE_INT:
			case TYPE_ADR:
				flags=1;
				break;
			case TYPE_DBL:
			case TYPE_FLT:
#if defined(__I386__)
				/*
				 * for i386 put all floats in memory
				 */
				flags=0;
				break;
#endif
				flags=2;
				break;
			default:
				{ log_text("Unknown Type\n"); assert(0); }
			}

			switch (flags) {
			case 0: /* lt_used[lt_used_index] -> lt_rest */
				ls->lt_mem[ ls->lt_mem_count++ ] = lt_index;
				break;
			case 1: /* l->lifetimes -> lt_int */
				ls->lt_int[ ls->lt_int_count++ ] = lt_index;
				break;
			case 2: /* l->lifetimes -> lt_flt */
				ls->lt_flt[ ls->lt_flt_count++ ] = lt_index;
				break;
			}


			if (lt->i_first_def == INT_MAX) {
#ifdef LSRA_DEBUG_VERBOSE
 				printf("Warning: var not defined! vi: %i start: %i end: %i\n", 
					   lt->v_index, lt->i_start, lt->i_end); 
#endif
				lt->bb_first_def = 0;
				lt->i_first_def = 0;
			}

  			lt->i_start = lt->i_first_def;

			if (lt->i_last_use == -2) {
#ifdef LSRA_DEBUG_VERBOSE
 				printf("Warning: Var not used! vi: %i start: %i end: %i\n", 
					   lt->v_index, lt->i_start, lt->i_end);
#endif
				lt->bb_last_use = lt->bb_first_def;
				lt->i_last_use = lt->i_first_def;
			}

			lt->i_end = lt->i_last_use;

#ifdef LSRA_DEBUG_VERBOSE
			if (lt->i_start > lt->i_end) 
				printf("Warning: last use before first def! vi: %i start: %i end: %i\n", lt->v_index, lt->i_start, lt->i_end);
#endif

#if !defined(LV)
			if ((lt->bb_first_def != lt->bb_last_use) ||
				(lt->i_first_def == -1)) {
				/* Lifetime goes over more than one Basic Block ->  */
				/* check for necessary extension over backedges     */
				/* see lsra_get_backedges                           */
				/* Arguments are set "before" Block 0, so they have */
				/* a lifespan of more then one block, too           */
				
				for (i=0; i < ls->backedge_count; i++) {
					if (!( (lt->bb_first_def > ls->backedge[i]->start) ||
						   (lt->bb_last_use < ls->backedge[i]->end) )) {
						/* Live intervall intersects with a backedge */
						/* 	if (lt->bb_first_def <= ls->backedge[i]->start) */
						if (lt->bb_last_use <= ls->backedge[i]->start)
							lt->i_end = 
								ls->icount_block[ls->backedge[i]->start] +
					  m->basicblocks[ls->sorted[ls->backedge[i]->start]].icount;
					}
				}
			}
#endif /* !defined(LV) */

#ifdef USAGE_PER_INSTR
			lt->usagecount = lt->usagecount / ( lt->i_end - lt->i_start + 1);
#endif
		}
	}
	ls->lifetimecount = lifetimecount;
}

#ifdef LSRA_DEBUG_VERBOSE
void print_lifetimes(jitdata *jd, int *lt, int lifetimecount)
{
	struct lifetime *n;
	int lt_index;
	int type,flags,regoff,varkind;

	lsradata     *ls;
	registerdata *rd;

	ls = jd->ls;
	rd = jd->rd;

	for (lt_index = 0; lt_index < lifetimecount; lt_index++) {
		n = &(ls->lifetime[lt[lt_index]]);
		if (n->savedvar == SAVEDVAR)
			printf("S");
		else
			printf(" ");
		if (n->v_index < 0) { /* stackslot */
			type = n->local_ss->s->type;
			flags=n->local_ss->s->flags;
			regoff=n->local_ss->s->regoff;
			varkind=n->local_ss->s->varkind;
		} else { /* local var */
			if (rd->locals[n->v_index][n->type].type>=0) {
				type = rd->locals[n->v_index][n->type].type;
				flags=rd->locals[n->v_index][n->type].flags;
				regoff=rd->locals[n->v_index][n->type].regoff;
				varkind=-1;
			} else 
				{ log_text("Type Data mismatch 3\n"); assert(0); }
		}
#if !defined(LV)
		printf("i_Start: %3i(%3i,%3i) i_stop: %3i(%3i,%3i) reg: %3i VI: %3i type: %3i flags: %3i varkind: %3i usage: %3li ltflags: %xi \n",n->i_start, ls->sorted[n->bb_first_def], n->i_first_def,n->i_end, ls->sorted[n->bb_last_use], n->i_last_use,regoff,n->v_index,type,flags, varkind, n->usagecount, n->flags);
#else
		printf("i_Start: %3i i_stop: %3i reg: %3i VI: %3i type: %3i flags: %3i varkind: %3i usage: %3li ltflags: %xi \n",n->i_start, n->i_end, regoff,n->v_index,type,flags, varkind, n->usagecount, n->flags);
#endif
	}
	printf( "%3i Lifetimes printed \n",lt_index);
}
#endif



/******************************************************************************
Helpers for first LSRA Version without exact Liveness Analysis
 *****************************************************************************/

#if !defined(LV)
bool lsra_join_ss( struct lsradata *ls, struct stackelement *in,
				   struct stackelement *out, int join_flag) {
	struct lifetime *lt, *lto;
	struct stackslot *ss, *ss_last;


	if (in->varnum != out->varnum) {
		lt = &(ls->lifetime[-in->varnum - 1]);
	
#ifdef LSRA_DEBUG_CHECK
		if (join_flag == JOIN_BB)
			if (lt->type == -1) { 
				log_text("lsra_join_ss: lifetime for instack not found\n");
				assert(0);
			}
#endif

		if (out->varnum >= 0) { /* no lifetime for this slot till now */
			lsra_add_ss(lt, out);
		} else {
			lto = &(ls->lifetime[-out->varnum - 1]);
			if ((join_flag == JOIN_DUP) || (join_flag == JOIN_OP))
				if ( (lt->flags & JOIN_BB) || (lto->flags & JOIN_BB)) {
					return false;
				}
			if (join_flag == JOIN_DUP)
				if ( (lt->flags & JOIN_OP) || (lto->flags & JOIN_OP)) {
					return false;
				}
#ifdef LSRA_DEBUG_CHECK
			if (lto->type == -1) {
				log_text("lsra_join_ss: lifetime for outstack not found\n");
				abort();
			}
#endif
#ifdef LSRA_DEBUG_CHECK
			if (lto->type != lt->type) {
				log_text("lsra_join_ss: in/out stack type mismatch\n");
				abort();
			}
#endif
	
			lt->flags |= JOINING;

			/* take Lifetime lto out of ls->lifetimes */
			lto->type = -1;

			/* merge lto into lt of in */

			ss_last = ss = lto->local_ss;
			while (ss != NULL) {
				ss_last = ss;
				ss->s->varnum = lt->v_index;
				ss = ss->next;
			}
			if (ss_last != NULL) {
				ss_last->next = lt->local_ss;
				lt->local_ss = lto->local_ss;
			}

			lt->savedvar |= lto->savedvar;
			lt->flags |= lto->flags | join_flag;
			lt->usagecount += lto->usagecount;

			/*join of i_first_def and i_last_use */
			if (lto->i_first_def < lt->i_first_def) {
				lt->i_first_def = lto->i_first_def;
			}	
			if (lto->i_last_use > lt->i_last_use) {
				lt->i_last_use = lto->i_last_use;
			}	
		}
	}
	return true;
}

/* join instack of Basic Block b_index with outstack of predecessors */
void lsra_join_lifetimes(jitdata *jd,int b_index) {
	methodinfo *m;
	lsradata *ls;
	struct stackelement *in, *i, *out;
    struct _list *pred;

	m  = jd->m;
	ls = jd->ls;

	/* do not join instack of Exception Handler */ 
	if (m->basicblocks[b_index].type == BBTYPE_EXH)
		return;
	in=m->basicblocks[b_index].instack;
	/* do not join first instack element of a subroutine header */
	if (m->basicblocks[b_index].type == BBTYPE_SBR)
		in=in->prev; 
	
	if (in != NULL) {
		for (pred = ls->pred[b_index]; pred != NULL; pred = pred->next) {
			out = m->basicblocks[pred->value].outstack;
			for (i=in; (i != NULL); i = i->prev, out=out->prev) {
				lsra_join_ss(ls, i, out, JOIN_BB);
			}
		}
	}
}

struct stackslot *lsra_make_ss(stackelement_t* s, int bb_index)
{
	struct stackslot *ss;

	ss = DNEW(struct stackslot);
	ss->bb = bb_index;
	ss->s  = s;
	return ss;
}

void lsra_add_ss(struct lifetime *lt, stackelement_t* s) {
	struct stackslot *ss;

	/* Stackslot not in list? */
	if (s->varnum != lt->v_index) {
		ss = DNEW(struct stackslot);
		ss->s = s;
		ss->s->varnum = lt->v_index;
		ss->next = lt->local_ss;
		lt->local_ss = ss;
		if (s != NULL) 
			lt->savedvar |= s->flags & SAVEDVAR;
		if (s != NULL) 
			lt->type = s->type;
	}
}

struct lifetime *get_ss_lifetime(lsradata *ls, stackelement_t* s) {
	struct lifetime *n;
	
	if (s->varnum >= 0) { /* new stackslot lifetime */
#ifdef LSRA_DEBUG_CHECK_VERBOSE
		if (-ls->v_index - 1 >= ls->maxlifetimes) {
			printf("%i %i\n", -ls->v_index - 1, ls->maxlifetimes);
		}
#endif
		_LSRA_ASSERT(-ls->v_index - 1 < ls->maxlifetimes);

		n = &(ls->lifetime[-ls->v_index - 1]);
		n->type = s->type;
		n->v_index = ls->v_index--;
		n->usagecount = 0;
		
		n->bb_last_use  = -1;
		n->bb_first_def = -1;
		n->i_last_use   = -2; /* At -1 param init happens, so -2 is below all
								 possible instruction indices */
		n->i_first_def  = INT_MAX;
		n->local_ss = NULL;
		n->savedvar = 0;
		n->flags    = 0;
	} else
		n = &(ls->lifetime[-s->varnum - 1]);

	lsra_add_ss( n, s);
	return n;
}

#define IS_TEMP_VAR(s) (((s)->varkind != ARGVAR) && ((s)->varkind != LOCALVAR))

#define lsra_join_3_stack(ls, dst, src1, src2, join_type) \
	if ( IS_TEMP_VAR(dst) ) { \
		join_ret = false; \
		if ( IS_TEMP_VAR(src1) && ((src1)->type == (dst)->type)) { \
			join_ret = lsra_join_ss(ls, dst, src1, join_type);								\
		} \
		if ((!join_ret) && IS_TEMP_VAR(src2) && ((src2)->type == (dst)->type)) { \
			lsra_join_ss(ls, dst, src2, join_type); \
		} \
	}

#define lsra_join_2_stack(ls, dst, src, join_type) \
	if ( IS_TEMP_VAR(dst) ) { \
		if ( (IS_TEMP_VAR(src)) && ((src)->type == (dst)->type)) {	\
			lsra_join_ss(ls, dst, src, join_type); \
		} \
	}

#define lsra_join_dup(ls, s1, s2, s3) {				   \
		if (IS_TEMP_VAR(s1)) {						   \
			join_ret = false;						   \
			if (IS_TEMP_VAR(s2))				       \
				join_ret = lsra_join_ss(ls, s1, s2, JOIN); \
			                         /* undangerous join!*/\
			if (IS_TEMP_VAR(s3)) {				       \
				if (join_ret)	/* first join succesfull -> second of type */ \
					            /* JOIN_DUP */			\
                    lsra_join_ss(ls, s1, s3, JOIN_DUP); \
				else									\
	                lsra_join_ss(ls, s1, s3, JOIN); /* first join did not */ \
				                          /* happen -> second undangerous */ \
		    }									        \
		}										        \
        if (IS_TEMP_VAR(s2) && IS_TEMP_VAR(s3))	        \
	        lsra_join_ss(ls, s2, s3, JOIN_DUP);		    \
	}

#define lsra_new_stack(ls, s, block, instr) \
	if ((s)->varkind != ARGVAR) _lsra_new_stack(ls, s, block, instr, LSRA_STORE)
void _lsra_new_stack(lsradata *ls, stackelement_t* s, int block, int instr, int store)
{
	struct lifetime *n;

	if (s->varkind == LOCALVAR) {
		lsra_usage_local(ls, s->varnum, s->type, block, instr, LSRA_STORE);
	} else /* if (s->varkind != ARGVAR) */ {
		
		n=get_ss_lifetime(ls, s);

		if (store == LSRA_BB_IN)
			n->flags |= JOIN_BB;
		/* remember first def -> overwrite everytime */
		n->bb_first_def = ls->sorted_rev[block];
		n->i_first_def = ls->icount_block[ls->sorted_rev[block]] + instr;

		n->usagecount+=ls->nesting[ls->sorted_rev[block]];
	}
}

#define lsra_from_stack(ls, s, block, instr) \
	if ((s)->varkind != ARGVAR) _lsra_from_stack(ls, s, block, instr, LSRA_LOAD)
#define lsra_pop_from_stack(ls, s, block, instr) \
	if ((s)->varkind != ARGVAR) _lsra_from_stack(ls, s, block, instr, LSRA_POP)
void _lsra_from_stack(lsradata *ls, stackelement_t* s, int block, int instr, int store)
{
	struct lifetime *n;

	if (s->varkind == LOCALVAR) {
		lsra_usage_local(ls, s->varnum, s->type, block, instr, LSRA_LOAD);
	} else /* if (s->varkind != ARGVAR) */ {
		if (s->varkind == STACKVAR )
			/* No STACKVARS possible with lsra! */
			s->varkind = TEMPVAR;

		n=get_ss_lifetime(ls, s);

		if (store == LSRA_BB_OUT)
			n->flags |= JOIN_BB;
		if (n->flags & JOINING)
			n->flags &= ~JOINING;
		n->usagecount+=ls->nesting[ls->sorted_rev[block]];

		/* remember last USE, so only write, if USE Field is undefined (==-1) */
		if (n->bb_last_use == -1) {
			n->bb_last_use = ls->sorted_rev[block];
			n->i_last_use = ls->icount_block[ls->sorted_rev[block]] + instr;
		}
	}
}

void lsra_usage_local(lsradata *ls, s4 v_index, int type, int block, int instr,
					  int store)
{
	struct lifetime *n;

	n = &(ls->lifetime[ ls->maxlifetimes + v_index * (TYPE_ADR+1) + type]);

	if (n->type == -1) { /* new local lifetime */
		n->local_ss=NULL;
		n->v_index=v_index;
		n->type=type;
		n->savedvar = SAVEDVAR;
		n->flags = 0;
		n->usagecount = 0;

		n->bb_last_use = -1;
		n->bb_first_def = -1;
		n->i_last_use = -2;
		n->i_first_def = INT_MAX;
	}
	n->usagecount+=ls->nesting[ls->sorted_rev[block]];
	/* add access at (block, instr) to instruction list */
	/* remember last USE, so only write, if USE Field is undefined (==-1)   */
	/* count store as use, too -> defined and not used vars would overwrite */
	/* other vars */
	if (n->bb_last_use == -1) {
		n->bb_last_use = ls->sorted_rev[block];
		n->i_last_use = ls->icount_block[ls->sorted_rev[block]] + instr;
	}
	if (store == LSRA_STORE) {
		/* store == LSRA_STORE, remember first def -> overwrite everytime */
		n->bb_first_def = ls->sorted_rev[block];
		n->i_first_def = ls->icount_block[ls->sorted_rev[block]] + instr;
	}
}	

#ifdef LSRA_DEBUG_VERBOSE
void lsra_dump_stack(stackelement_t* s)
{
	while (s!=NULL) {
		printf("%p(R%3i N%3i K%3i T%3i F%3i) ",(void *)s,s->regoff, s->varnum, 
			   s->varkind, s->type, s->flags);
		s=s->prev;
	}
	printf("\n");
}
#endif


void lsra_scan_registers_canditates(jitdata *jd, int b_index)
{
/* 	methodinfo         *lm; */
	builtintable_entry *bte;
	methoddesc         *md;
	int i;
	int opcode;
	int iindex;
	stackelement_t*    src;
	stackelement_t*    dst;
	instruction *iptr;
	bool join_ret; /* for lsra_join* Macros */
	methodinfo *m;
	lsradata *ls;

	m  = jd->m;
	ls = jd->ls;

    /* get instruction count for BB and remember the max instruction count */
	/* of all BBs */
	iindex = m->basicblocks[b_index].icount - 1;

	src = m->basicblocks[b_index].instack;
	if (m->basicblocks[b_index].type != BBTYPE_STD) {
		lsra_new_stack(ls, src, b_index, 0);
		src = src->prev;
	}
	for (;src != NULL; src=src->prev) {
/*******************************************************************************
Check this - ? For every incoming Stack Slot a lifetime has to be created ?
*******************************************************************************/
			_lsra_new_stack(ls, src, b_index, 0, LSRA_BB_IN);
	}
	src = m->basicblocks[b_index].outstack;
	for (;src != NULL; src=src->prev) {
			_lsra_from_stack(ls, src, b_index, iindex, LSRA_BB_OUT);
	}

	/* set iptr to last instruction of BB */
	iptr = m->basicblocks[b_index].iinstr + iindex;

	for (;iindex >= 0; iindex--, iptr--)  {

		/* get source and destination Stack for the current instruction     */
		/* destination stack is available as iptr->dst                      */

		dst = iptr->dst;

		/* source stack is either the destination stack of the previos      */
		/* instruction, or the basicblock instack for the first instruction */

		if (iindex) /* != 0 is > 0 here, since iindex ist always >= 0 */
			src=(iptr-1)->dst;
		else
			src=m->basicblocks[b_index].instack;
		opcode = iptr->opc;


		switch (opcode) {

			/* pop 0 push 0 */
		case ICMD_RET:
			/* local read (return adress) */
			lsra_usage_local(ls, iptr->op1, TYPE_ADR, b_index, iindex,
							 LSRA_LOAD);
			break;
		case ICMD_NOP:
/* 		case ICMD_ELSE_ICONST: */
		case ICMD_CHECKNULL:
		case ICMD_JSR:
		case ICMD_RETURN:
		case ICMD_GOTO:
		case ICMD_PUTSTATICCONST:
		case ICMD_INLINE_START:
		case ICMD_INLINE_END:
		case ICMD_INLINE_GOTO:
			break;
                             
		case ICMD_IINC:
			/* local = local+<const> */
			lsra_usage_local(ls, iptr->op1, TYPE_INT, b_index, iindex, 
							 LSRA_LOAD);
			lsra_usage_local(ls, iptr->op1, TYPE_INT, b_index, iindex, 
							 LSRA_STORE);
			break;

			/* pop 0 push 1 const: const->stack */
		case ICMD_ICONST:
		case ICMD_LCONST:
		case ICMD_FCONST:
		case ICMD_DCONST:
		case ICMD_ACONST:
			/* new stack slot */
			lsra_new_stack(ls, dst, b_index, iindex);
			break;

			/* pop 0 push 1 load: local->stack */
		case ICMD_ILOAD:
		case ICMD_LLOAD:
		case ICMD_FLOAD:
		case ICMD_DLOAD:
		case ICMD_ALOAD:
			if (dst->varkind != LOCALVAR) {
				/* local->value on stack */
				lsra_usage_local(ls, iptr->op1, opcode - ICMD_ILOAD, b_index, 
								 iindex, LSRA_LOAD);
				lsra_new_stack(ls, dst, b_index, iindex); /* value->stack */
			} else /* if (dst->varnum != iptr->op1) */ {
				/* local -> local */
				lsra_usage_local(ls, iptr->op1, opcode - ICMD_ILOAD, b_index, 
								 iindex,LSRA_LOAD); /* local->value */
				lsra_usage_local(ls, dst->varnum, opcode - ICMD_ILOAD, b_index,
								 iindex, LSRA_STORE); /* local->value */
			}

			break;

			/* pop 2 push 1 */
			/* Stack(arrayref,index)->stack */
		case ICMD_IALOAD:
		case ICMD_LALOAD:
		case ICMD_FALOAD:
		case ICMD_DALOAD:
		case ICMD_AALOAD:

		case ICMD_BALOAD:
		case ICMD_CALOAD:
		case ICMD_SALOAD:
			/* stack->index */
			lsra_from_stack(ls, src, b_index, iindex); 
			/* stack->arrayref */
			lsra_from_stack(ls, src->prev, b_index, iindex); 
			/* arrayref[index]->stack */
			lsra_new_stack(ls, dst, b_index, iindex); 
			break;

			/* pop 3 push 0 */
			/* stack(arrayref,index,value)->arrayref[index]=value */
		case ICMD_IASTORE:
		case ICMD_LASTORE:
		case ICMD_FASTORE:
		case ICMD_DASTORE:
		case ICMD_AASTORE:

		case ICMD_BASTORE:
		case ICMD_CASTORE:
		case ICMD_SASTORE:

			lsra_from_stack(ls, src,b_index, iindex); /* stack -> value */
			lsra_from_stack(ls, src->prev, b_index, iindex); /* stack -> index*/
			/* stack -> arrayref */
			lsra_from_stack(ls, src->prev->prev, b_index, iindex); 
			break;

			/* pop 1 push 0 store: stack -> local */
		case ICMD_ISTORE:
		case ICMD_LSTORE:
		case ICMD_FSTORE:
		case ICMD_DSTORE:
		case ICMD_ASTORE:
			if (src->varkind != LOCALVAR) {
				lsra_from_stack(ls, src, b_index, iindex); /* stack -> value */
				lsra_usage_local(ls, iptr->op1, opcode-ICMD_ISTORE, b_index,
								 iindex, LSRA_STORE); /* local->value */
			} else /* if (src->varnum != iptr->op1) */ {
				lsra_usage_local(ls, iptr->op1, opcode-ICMD_ISTORE, b_index, 
								 iindex, LSRA_STORE); /* local->value */
				lsra_usage_local(ls, src->varnum, opcode-ICMD_ISTORE, b_index, 
								 iindex, LSRA_LOAD); /* local->value */
			}
			break;

			/* pop 1 push 0 */
		case ICMD_POP: /* throw away a stackslot */
			/* TODO: check if used anyway (DUP...) and change codegen to */
			/*       ignore this stackslot */
			lsra_pop_from_stack(ls, src, b_index, iindex);
			break;

			/* pop 1 push 0 */
		case ICMD_IRETURN:
		case ICMD_LRETURN:
		case ICMD_FRETURN:
		case ICMD_DRETURN:
		case ICMD_ARETURN: /* stack(value) -> [empty]    */

		case ICMD_ATHROW:  /* stack(objref) -> undefined */

		case ICMD_PUTSTATIC: /* stack(value) -> static_field */
		case ICMD_PUTFIELDCONST:

			/* pop 1 push 0 branch */
		case ICMD_IFNULL: /* stack(value) -> branch? */
		case ICMD_IFNONNULL:

		case ICMD_IFEQ:
		case ICMD_IFNE:
		case ICMD_IFLT:
		case ICMD_IFGE:
		case ICMD_IFGT:
		case ICMD_IFLE:

		case ICMD_IF_LEQ:
		case ICMD_IF_LNE:
		case ICMD_IF_LLT:
		case ICMD_IF_LGE:
		case ICMD_IF_LGT:
		case ICMD_IF_LLE:

			/* pop 1 push 0 table branch */
		case ICMD_TABLESWITCH:
		case ICMD_LOOKUPSWITCH:

		case ICMD_MONITORENTER:
		case ICMD_MONITOREXIT:
			lsra_from_stack(ls, src, b_index, iindex); /* stack -> value */
			break;

			/* pop 2 push 0 */
		case ICMD_POP2: /* throw away 2 stackslots */
			/* TODO: check if used anyway (DUP...) and change codegen to */
			/*       ignore this stackslot */
			lsra_pop_from_stack(ls, src, b_index, iindex);
			lsra_pop_from_stack(ls, src->prev, b_index, iindex);
			break;

			/* pop 2 push 0 branch */

		case ICMD_IF_ICMPEQ: /* stack (v1,v2) -> branch(v1,v2) */
		case ICMD_IF_ICMPNE:
		case ICMD_IF_ICMPLT:
		case ICMD_IF_ICMPGE:
		case ICMD_IF_ICMPGT:
		case ICMD_IF_ICMPLE:

		case ICMD_IF_LCMPEQ:
		case ICMD_IF_LCMPNE:
		case ICMD_IF_LCMPLT:
		case ICMD_IF_LCMPGE:
		case ICMD_IF_LCMPGT:
		case ICMD_IF_LCMPLE:

		case ICMD_IF_ACMPEQ:
		case ICMD_IF_ACMPNE:

			/* pop 2 push 0 */
		case ICMD_PUTFIELD: /* stack(objref,value) -> objref = value */

		case ICMD_IASTORECONST:
		case ICMD_LASTORECONST:
		case ICMD_AASTORECONST:
		case ICMD_BASTORECONST:
		case ICMD_CASTORECONST:
		case ICMD_SASTORECONST:
			lsra_from_stack(ls, src, b_index, iindex); 	   /* stack -> value*/
			lsra_from_stack(ls, src->prev, b_index, iindex); 
			break;

			/* pop 0 push 1 dup */
		case ICMD_DUP: /* src == dst->prev, src -> dst */
			/* lsra_from_stack(ls, src,b_index,iindex);*/ 
			lsra_new_stack(ls, dst, b_index, iindex);

#ifdef JOIN_DUP_STACK
			/* src is identical to dst->prev */
			lsra_join_2_stack(ls, src, dst, JOIN_DUP);
#endif
			break;

			/* pop 0 push 2 dup */
		case ICMD_DUP2: 
			/* lsra_from_stack(ls, src,b_index, iindex); */ 
			/* lsra_from_stack(ls, src->prev, b_index, iindex); */
			lsra_new_stack(ls, dst->prev, b_index, iindex);
			lsra_new_stack(ls, dst, b_index, iindex); 

#ifdef JOIN_DUP_STACK
			lsra_join_2_stack(ls, src, dst, JOIN_DUP);
			lsra_join_2_stack(ls, src->prev, dst->prev, JOIN_DUP);
			/* src is identical to dst->prev->prev */
			/* src->prev is identical to dst->prev->prev->prev */
#endif
			break;

			/* pop 2 push 3 dup */
		case ICMD_DUP_X1:
			lsra_from_stack(ls, src, b_index, iindex+1); 
			lsra_from_stack(ls, src->prev, b_index, iindex+1);
			lsra_new_stack(ls, dst->prev->prev, b_index, iindex);
			lsra_new_stack(ls, dst->prev, b_index, iindex);
			lsra_new_stack(ls, dst, b_index, iindex); 
#ifdef JOIN_DUP_STACK
			lsra_join_dup(ls, src, dst, dst->prev->prev);
			lsra_join_2_stack(ls, src->prev, dst->prev, JOIN);
#endif
			break;

			/* pop 3 push 4 dup */
		case ICMD_DUP_X2:
			lsra_from_stack(ls, src,b_index, iindex+1); 
			lsra_from_stack(ls, src->prev, b_index, iindex+1); 
			lsra_from_stack(ls, src->prev->prev, b_index, iindex+1); 
			lsra_new_stack(ls, dst->prev->prev->prev, b_index, iindex);
			lsra_new_stack(ls, dst->prev->prev, b_index, iindex);
			lsra_new_stack(ls, dst->prev, b_index, iindex);
			lsra_new_stack(ls, dst, b_index, iindex); 

#ifdef JOIN_DUP_STACK
			lsra_join_dup(ls, src, dst, dst->prev->prev->prev);
			lsra_join_2_stack(ls, src->prev, dst->prev, JOIN);
			lsra_join_2_stack(ls, src->prev->prev, dst->prev->prev, JOIN);
#endif
			break;

			/* pop 3 push 5 dup */
		case ICMD_DUP2_X1:
			lsra_from_stack(ls, src, b_index, iindex+1); 
			lsra_from_stack(ls, src->prev, b_index, iindex+1); 
			lsra_from_stack(ls, src->prev->prev, b_index, iindex+1); 
			lsra_new_stack(ls, dst->prev->prev->prev->prev, b_index, iindex);
			lsra_new_stack(ls, dst->prev->prev->prev, b_index, iindex);
			lsra_new_stack(ls, dst->prev->prev, b_index, iindex);
			lsra_new_stack(ls, dst->prev, b_index, iindex);
			lsra_new_stack(ls, dst, b_index, iindex); 

#ifdef JOIN_DUP_STACK
			lsra_join_dup(ls, src, dst, dst->prev->prev->prev);
			lsra_join_dup(ls, src->prev, dst->prev, 
						  dst->prev->prev->prev->prev);
			lsra_join_2_stack(ls, src->prev->prev, dst->prev->prev, JOIN);
#endif
			break;

			/* pop 4 push 6 dup */
		case ICMD_DUP2_X2:
			lsra_from_stack(ls, src, b_index, iindex+1); 
			lsra_from_stack(ls, src->prev, b_index, iindex+1); 
			lsra_from_stack(ls, src->prev->prev, b_index, iindex+1); 
			lsra_from_stack(ls, src->prev->prev->prev, b_index, iindex+1); 
			lsra_new_stack(ls, dst->prev->prev->prev->prev->prev, b_index, 
						   iindex);
			lsra_new_stack(ls, dst->prev->prev->prev->prev, b_index, iindex);
			lsra_new_stack(ls, dst->prev->prev->prev, b_index, iindex);
			lsra_new_stack(ls, dst->prev->prev, b_index, iindex);
			lsra_new_stack(ls, dst->prev, b_index, iindex);
			lsra_new_stack(ls, dst, b_index, iindex); 

#ifdef JOIN_DUP_STACK
			lsra_join_dup(ls, src, dst, dst->prev->prev->prev->prev);
			lsra_join_dup(ls, src->prev, dst->prev,
						  dst->prev->prev->prev->prev->prev);
			lsra_join_2_stack(ls, src->prev->prev, dst->prev->prev, JOIN);
			lsra_join_2_stack(ls, src->prev->prev->prev, dst->prev->prev->prev, 
							  JOIN);
#endif
			break;

			/* pop 2 push 2 swap */
		case ICMD_SWAP:
			lsra_from_stack(ls, src, b_index, iindex+1); 
			lsra_from_stack(ls, src->prev, b_index, iindex+1);
			lsra_new_stack(ls, dst->prev, b_index, iindex);
			lsra_new_stack(ls, dst, b_index, iindex);

			lsra_join_2_stack(ls, src->prev, dst, JOIN);
			lsra_join_2_stack(ls, src, dst->prev, JOIN);

			break;

			/* pop 2 push 1 */
					
		case ICMD_LADD:
		case ICMD_LSUB:
		case ICMD_LMUL:

		case ICMD_LOR:
		case ICMD_LAND:
		case ICMD_LXOR:

		case ICMD_LSHL:
		case ICMD_LSHR:
		case ICMD_LUSHR:

		case ICMD_IADD:
		case ICMD_IMUL:

		case ICMD_ISHL:
		case ICMD_ISHR:
		case ICMD_IUSHR:
		case ICMD_IAND:
		case ICMD_IOR:
		case ICMD_IXOR:


		case ICMD_FADD:
		case ICMD_FSUB:
		case ICMD_FMUL:

		case ICMD_DADD:
		case ICMD_DSUB:
		case ICMD_DMUL:
		case ICMD_DDIV:
		case ICMD_DREM:
			lsra_from_stack(ls, src, b_index, iindex);
			lsra_from_stack(ls, src->prev, b_index, iindex);
			lsra_new_stack(ls, dst, b_index, iindex);
#ifdef JOIN_DEST_STACK
			lsra_join_3_stack(ls, dst, src->prev, src, JOIN_OP);
#endif
			break;

		case ICMD_ISUB:
			lsra_from_stack(ls, src, b_index, iindex);
			lsra_from_stack(ls, src->prev,b_index,iindex);
			lsra_new_stack(ls, dst, b_index, iindex);
#ifdef JOIN_DEST_STACK
			lsra_join_2_stack(ls, src, dst, JOIN_OP);
#endif
			break;

		case ICMD_LDIV:
		case ICMD_LREM:

		case ICMD_IDIV:
		case ICMD_IREM:

		case ICMD_FDIV:
		case ICMD_FREM:

		case ICMD_LCMP:
		case ICMD_FCMPL:
		case ICMD_FCMPG:
		case ICMD_DCMPL:
		case ICMD_DCMPG:
			lsra_from_stack(ls, src, b_index, iindex);
			lsra_from_stack(ls, src->prev, b_index, iindex);
			lsra_new_stack(ls, dst, b_index, iindex);
			break;

			/* pop 1 push 1 */
		case ICMD_LADDCONST:
		case ICMD_LSUBCONST:
		case ICMD_LMULCONST:
		case ICMD_LMULPOW2:
		case ICMD_LDIVPOW2:
		case ICMD_LREMPOW2:
		case ICMD_LANDCONST:
		case ICMD_LORCONST:
		case ICMD_LXORCONST:
		case ICMD_LSHLCONST:
		case ICMD_LSHRCONST:
		case ICMD_LUSHRCONST:

		case ICMD_IADDCONST:
		case ICMD_ISUBCONST:
		case ICMD_IMULCONST:
		case ICMD_IMULPOW2:
		case ICMD_IDIVPOW2:
		case ICMD_IREMPOW2:
		case ICMD_IANDCONST:
		case ICMD_IORCONST:
		case ICMD_IXORCONST:
		case ICMD_ISHLCONST:
		case ICMD_ISHRCONST:
		case ICMD_IUSHRCONST:

/* 		case ICMD_IFEQ_ICONST: */
/* 		case ICMD_IFNE_ICONST: */
/* 		case ICMD_IFLT_ICONST: */
/* 		case ICMD_IFGE_ICONST: */
/* 		case ICMD_IFGT_ICONST: */
/* 		case ICMD_IFLE_ICONST: */

		case ICMD_INEG:
		case ICMD_INT2BYTE:
		case ICMD_INT2CHAR:
		case ICMD_INT2SHORT:
		case ICMD_LNEG:
		case ICMD_FNEG:
		case ICMD_DNEG:

		case ICMD_I2L:
		case ICMD_I2F:
		case ICMD_I2D:
		case ICMD_L2I:
		case ICMD_L2F:
		case ICMD_L2D:
		case ICMD_F2I:
		case ICMD_F2L:
		case ICMD_F2D:
		case ICMD_D2I:
		case ICMD_D2L:
		case ICMD_D2F:

		case ICMD_CHECKCAST:
			lsra_from_stack(ls, src, b_index, iindex);
			lsra_new_stack(ls, dst, b_index, iindex);
#ifdef JOIN_DEST_STACK
			lsra_join_2_stack(ls, src, dst, JOIN_OP);
#endif
			break;

			/* TODO: check if for these ICMDs JOIN_DEST_STACK works, too! */
		case ICMD_ARRAYLENGTH:
		case ICMD_INSTANCEOF:

		case ICMD_NEWARRAY:
		case ICMD_ANEWARRAY:

		case ICMD_GETFIELD:
			lsra_from_stack(ls, src, b_index, iindex);
			lsra_new_stack(ls, dst, b_index, iindex);
			break;

			/* pop 0 push 1 */
		case ICMD_GETSTATIC:

		case ICMD_NEW:
			lsra_new_stack(ls, dst, b_index, iindex);
			break;

			/* pop many push any */

		case ICMD_INVOKESTATIC:
		case ICMD_INVOKESPECIAL:
		case ICMD_INVOKEVIRTUAL:
		case ICMD_INVOKEINTERFACE:
			INSTRUCTION_GET_METHODDESC(iptr,md);
			i = md->paramcount;
			while (--i >= 0) {
				lsra_from_stack(ls, src, b_index, iindex);
				src = src->prev;
			}
			if (md->returntype.type != TYPE_VOID)
				lsra_new_stack(ls, dst, b_index, iindex);
			break;


		case ICMD_BUILTIN:
			bte = iptr->val.a;
			md = bte->md;
			i = md->paramcount;
			while (--i >= 0) {
				lsra_from_stack(ls, src, b_index, iindex);
				src = src->prev;
			}
			if (md->returntype.type != TYPE_VOID)
				lsra_new_stack(ls, dst, b_index, iindex);
			break;

		case ICMD_MULTIANEWARRAY:
			i = iptr->op1;
			while (--i >= 0) {
				lsra_from_stack(ls, src, b_index, iindex);
				src = src->prev;
			}
			lsra_new_stack(ls, dst, b_index, iindex);
			break;

		default:
			exceptions_throw_internalerror("Unknown ICMD %d during register allocation",
										   iptr->opc);
			return;
		} /* switch */
	}
}
#endif /* defined(LV) */


/*
 * These are local overrides for various environment variables in Emacs.
 * Please do not remove this and leave it at the end of the file, where
 * Emacs will automagically detect them.
 * ---------------------------------------------------------------------
 * Local variables:
 * mode: c
 * indent-tabs-mode: t
 * c-basic-offset: 4
 * tab-width: 4
 * End:
 * vim:noexpandtab:sw=4:ts=4:
 */
