
/*
 * Copyright (c) 1988 by Sozobon, Limited.  Author: Joseph M Treat
 *
 * Permission is granted to anyone to use this software for any purpose
 * on any computer system, and to redistribute it freely, with the
 * following restrictions:
 * 1) No charge may be made other than reasonable charges for reproduction.
 * 2) Modified versions must be clearly marked as such.
 * 3) The authors are not responsible for any harmful consequences
 *    of using this software, even if they result from defects in it.
 */

#include "jas.h"

BRANCH *brlist = (BRANCH *) NULL;

add_brnch( cptr, where )
	CBUF *cptr;
	long where;
{
	register BRANCH *bp;

	bp = ALLO(BRANCH);

	bp->where = where;
	bp->cptr = cptr;
	bp->link = brlist;
	brlist = bp;
}

do_opt()
{
	BRANCH *bp, **lbp;
	register CBUF *cp;
	SYM *sp;
	register int changed = 0;
	extern long dottxt;

	/* 
	 * first take care of jsr's to external routines
	 */
	lbp = &brlist;
	for ( bp = brlist; bp != (BRANCH *) NULL; bp = bp->link ) {
		cp = bp->cptr;
		if ( cp->value.value != 0x61 /* BSR */ ) {
			lbp = &bp->link;
			continue;
		}
		sp = cp[1].value.psym;
		if ( sp->flags & SEGMT ) {
			lbp = &bp->link;
			continue;
		}
		/* 
		 * change it to a jsr
		 */
		cp[0].nbits = 16;
		cp[0].value.value = 0x4eb9;	/* jsr abs.l */
		cp[1].nbits = 32;
		cp[1].action = GENRELOC;
		dottxt += 4;
		/*
		 * move all text symbols after this point up four bytes
		 */
		fixsymval( bp->where, 4L, TXT );
		/*
		 * move the location of all branches after this point up
		 */
		{
			register BRANCH *xbp;

			for ( xbp = brlist; xbp != bp; xbp = xbp->link )
				xbp->where += 4;
		}
		/*
		 * remove this entry from the branch list
		 */
		*lbp = bp->link;
		/*
		 * don't bother to free it, it will just make later ALLO's 
		 * slower
		 */
	}
	/* 
	 * now do normal branches and remaining bsr's
	 */
	do {
		changed = 0;

		lbp = &brlist;
		for ( bp = brlist; bp != (BRANCH *) NULL; bp = bp->link ) {
			register long val;

			cp = bp->cptr;
			sp = cp[1].value.psym;

			val = cp[1].value.value + sp->value - bp->where;
			if ( val >= -128 && val <= 127 && val != 0 ) {
				lbp = &bp->link;
				continue;
			}
			/* 
			 * change it to a 16-bit displacement
			 */
			cp[0].nbits = 16;
			cp[0].value.value <<= 8;
			cp[1].nbits = 16;
			cp[1].action = GENPCREL;
			dottxt += 2;
			/*
			 * move all text symbols after this point up two bytes
			 */
			fixsymval( bp->where, 2L, TXT );
			/*
			 * move the location of all branches after this point up
			 */
			{
				register BRANCH *xbp;
	
				for ( xbp = brlist; xbp != bp; xbp = xbp->link )
					xbp->where += 2;
			}
			/*
			 * remove this entry from the branch list
			 */
			*lbp = bp->link;
			changed = 1;
		}

	} while ( changed );
}
