


/* EPC Imp to C Translation Release 4 Version Apr 95 */


#include "imptoc.h"

#undef PI

/** 02Sep97 - p5procs06.5.2                                                  */
/**           Correction in Improve Compares for Byte conparison             */
/**           Changes in wrapping to help keep stack 8 byte aligned          */
/**           and to support microsofts STDCALL                              */

/** 16Jul97 - p5procs06.5.1                                                  */
/**           Two minor bug fixes in loopopt (Hoisting from conde sections   */
/**           and cleanupfrag (Care with nextinstr being NULL                */
/**           More care in tail recursion                                    */
/**           Care in Doubledefs over dead instrs which change FSTP          */
/** 08Jul97 - p5procs06.5                                                    */
/**           Don't make the instruction generated by makefpop potentially   */
/**           deleteable since FP stack must *always* be tidied up.          */
/**           Use Breconvergeliveness not Bupdate.. in InproveCondEstablish  */
/**           since several frags have been changed.                         */
/**           Watch for FISTPd in peepholer since this instr is notstandard  */
/**           Also avoid popping params into edx if a LONGINT is returned    */
/** 10Jun97 - p5rocs06.4                                                     */
/**           More effort in Cvalidate jumps to get correct jump size        */
/** 09May97 - p5procs06.3.2                                                  */
/**           Moved one assembler optimisation to Cestablishca from finaltidy*/
/**           so that Calums exceptions tables keep the right offset with -g */
/**           Also take more care when putting out .aligns in the code       */
/** 24Mar97 - p5procs06.3.1                                                  */
/**           Checked for redundant test instructions in cleanupfrag         */
/**           Added the AND by 2**N CMP 2**N optimisation for GPT            */
/** 20Nov96 - p5procs06.3                                                    */
/**           Removed BARRIER FLAG from exit sequence for better schedules   */
/** 24Oct96 - Flattening for translation to c    p5procs06.2                 */
/** 16Oct96 - PIC used via external var. extensions for GPT&DG               */
/** 02Jly96 - P5procs06                                                      */
/**           More work on loopopt                                           */
/** 18Jun96 - p5procs05.1                                                    */
/**           Constrain loopopt so as not to expand the wrappers(pds)        */
/**           Handle LEAs correctly in 'improve leafentry'                   */
/**           Minor changes to Assembler for Lynxos                          */
/** 22Feb95 - p5procs05                                                      */
/**           Changes to improve performace for DG and others including      */
/**           use of the Beta registers to model AGI delays(pds)             */
/** 31Jan95 - p5procs04.5.i                                                  */
/**           Changes to exit wrapper not to rely on ESP                     */
/** 24Nov95 - p5procs04.4.i                                                  */
/**           Additional optimisations for bits and bytes using movb         */
/** 10Nov95 - p5procs04.3.i                                                  */
/**           Used TargetABI to get minor differences for DG-UX operating sys*/
/** 28Jly95 - Added peepholing to delete redundant real truncates            */
/** 31May95 - P5reinitialise added and asstext changed for GNU as p5rprocs04.1.i*/
/** 09Sep94 - Changes for Pentium Specific optimisations p5procs04.i         */
/** 25Mar94 - Changes for new GIS bprocs              p5procs02.i            */
/***/
/***/
/** 27/10/91 - base version p5procs01.i   (derived loosely from mipsprocs9)  */
/***/
#define modulename ("targetprocs")
/***/
#include "cgtarget.h"
/***/
#include "cgconsts.h"
/***/
#include "archdefs.h"
#include "boconsts.h"
/***/
/***/
#define optimtrace 1
/***/
/***/
/**************************************************************************/
/**                                                                      **/
/**              Imports                                                 **/
/**                                                                      **/
/**************************************************************************/
/***/
/***/
#include"prototypes.h"
/***/
extern int RegClaimMaskA;
extern int RegClaimMaskB;
/*   %EXTERNALINTEGERSPEC lowfreg,lowreg, saveparams, paramssaved            */
extern int diagnostics;
extern int UnkCntrlFlow;
/***/
/***/
/***/
/********************************************************************************/
/**                                                                            **/
/**          CONSTANTS FOR FUNCTIONAL INTERFACE TO GLOBAL SCHEDULER            **/
/**                                                                            **/
/********************************************************************************/
/***/
/** Bit values for bit vector information passed to global scheduler         */
/***/
/** Values for GetAccessInfo                                                 */
#define AILITOFFSET (1<<0)	/*access has a literal offset       */
#define AIFIXOFFSET (1<<1)	/*access has a fixup displacement   */
#define AISCALED (1<<2)	/*access has scaled register offset */
#define AIVOLATILE (1<<3)	/*access is to volatile location    */
#define AITSAACCESS (1<<4)	/*access is to TSA                  */
#define AIDBLIND (1<<5)	/*access is doubly indirect         */
#define AIDOMEXCL (1<<6)	/*access is domain exclusive        */
/***/
/** Values for GetFragProps                                                  */
#define FPFALLSTHROUGH (1<<0)	/*frag falls through to successor   */
#define FPFALLENINTO (1<<1)	/*frag fallen into from predecessor */
#define FPNOGIS (1<<2)	/*frag should not be globally sched */
#define FPRETURNS (1<<3)	/*frag does a function return       */
#define FPRETBRANCH (1<<4)	/*frag does a branch to a return    */
/***/
/***/
/** Values for GetOperands                                                   */
/***/
/**    Definition of operand types: 00 - single register                     */
/**                                 01 - exempt register                     */
/**                                 10 - register pair                       */
/**                                 11 - register quad                       */
/***/
#define OPTYPE0 (1<<0)	/*operand type LSB                  */
#define OPTYPE1 (1<<1)	/*operand type MSB                  */
#define OPFIXED (1<<2)	/*operand has fixed allocation      */
#define OPALIGN (1<<3)	/*operand requires size alignment   */
#define OPTARGET (1<<4)	/*operand is part of destination    */
#define OPSPECIAL (1<<5)	/*operand has a beta alias or undefs*/
/*other half of a register pair     */
#define OPREAD (1<<6)	/*operand is read                   */
#define OPWRITE (1<<7)	/*operand is written                */
/***/
/** Constant to represent unchanged operands                                 */
#define NONEWREG 255
/***/
/***/
/**************************************************************************/
/**                                                                      **/
/**              Global data                                             **/
/**                                                                      **/
/**************************************************************************/
/***/

#if(optimtrace!=0) 
#define bannerline ("------------------------------------------------------------------------------")

#endif;
/***/
static unsigned char codebuff [1059+1];
static int bbschedule;
static int gschedule;
static int leafopt;
static int peepopt;
static int ProcNum;
static int firstentry;
static int buffptr;
static int baseca;
static int latestlineno;
static int setdbx;
static int miscreport;
static int hazardreport;
static int peepreport;	/* controls local diagnostic printing           */
static int globreport;	/* controls global diagnostic printing          */
static int asmlist;	/* controls production of address-less asm list */
extern int Pic;	/*0 => defaults/ >0 => generate pic             */
static int lastlocalcallra=0;	/* Point from where switch access calculated    */
static int wrappediregs=0;	/* Defines regs saved in wrappers */
static int wrappertype;	/* Defines wrappers as follows :-         */
/* 0=normal, 1=uses esp as ebp, 2=no frame*/
static struct procfmt *PI;
static struct procfmt *outerPI;
/***/
#define alloworphans 1	/* change to 0 to prevent orphaned relocations  */
/***/
#define STDOUT 1
#define HT 9	/* Horizontal Tab*/
#define SENSIBLEITER 1000
#define Normalfix 0
#define Gotrelfix 7
#define dcallfix 3
#define idcallfix 5
#define GOTfix 6
#define GOTofffix 4
/***/

#if((TargetABI==DGUXABI)||(TargetABI==LynxOS)) 
#define commentmark (" #")

#else
#define commentmark (" /")

#endif;

/***/
static const unsigned char InverseJump [JG-(JO)+1] = {
	JNO,
	JO,JNB,JB,JNE,JE,JA,0,
	JBE,JNS,JS,JNP,JP,JGE,JL,JG,
	JLE};
static const unsigned char setjump [JG-(JO)+1] = {
	SETO,
	SETNO,SETB,SETNB,SETE,SETNEQ,SETBE,0,
	SETA,SETS,SETNS,SETP,SETNP,SETL,SETGE,SETLEQ,
	SETG};
/***/
/***/
/********************************************************/
/** Arrays for returning results from p5 GetOperands **/
/********************************************************/
/***/
/***/
/***/
/********************************************************/
/** Globals for Stack Frame Store Instructions         **/
/********************************************************/
/***/
extern unsigned char StackSTflags [256+1];
/*Records how the stack or parameter locations have been accessed:*/
/* Bit 0 - store flag                                             */
/* Bit 1 - load flag                                              */
/* Bit 2 - address taken flag                                     */
/***/
/***/
/********************************************************/
/** Globals for Recording Parameter Store Instructions **/
/********************************************************/
/***/
int ParamSTMmarkers [(((unsigned)Regparamsize>>2)-1)+1];
/*records the location of the STore instruction*/
/*    for each parameter register              */
unsigned char paramSTflags [(((unsigned)Regparamsize>>2)-1)+1];
/*Records how the parameters have been accessed:*/
/* Bit 0 - store flag                           */
/* Bit 1 - load flag                            */
/* Bit 2 - address taken flag                   */
/***/
/***/
/***/
void reintegrateregmasks( struct fragfmt * );
static int DoLeafOpt( struct fragfmt * );
/***/
/***/
/**************************************************************************/
/**                                                                      **/
/**              Initialisation                                          **/
/**                                                                      **/
/**************************************************************************/
/***/
/***/
static void phex(int val){
	printf("%8X",val);
}
static char * itos(int val){
      static char sp[20];
      sprintf(sp,"%d",val);
      return sp;
}
void p5init(int options) {
	/***************************************************************************/
	/** called by MSetOptions                                                 **/
	/** options have bit value significance                                   **/
	/**   x'00000001'  enable miscellaneous architecture specific tracing     **/
	/**   x'00000002'  generate assembly listing for each frag                **/
	/**   x'00000004'  enable peephole optimisation tracing                   **/
	/**   x'00000008'  parameters are independent (FORTRAN only)              **/
	/**   x'00000010'  enable put memory allocation tracing                   **/
	/**   x'00000080'  enable put file monitoring                             **/
	/**   x'00000100'  enable global scheduling                               **/
	/**   x'00000200'  enable leaf routine optimisation                       **/
	/**   x'00000400'  enable peephole optimisation                           **/
	/**   x'00010000'  profiling                                              **/
	/**   x'00020000'  enable DBX/SDB information generation                  **/
	/**   x'00040000'  minimum diags preparation                              **/
	/**   x'00080000'  dynamic line number updating                           **/
	/**   x'00100000'  prepare static line no table (later)                   **/
	/**   x'00200000'  support overflow checking                              **/
	/**   x'00400000'  allow compiler allocation of registers (FORTRAN only)  **/
	/**   x'00800000'  set FPU traps if compiling a main program              **/
	/**   x'01000000'  enable basic block instruction scheduling              **/
	/**   x'02000000'  prepare for FORTRAN argument checking                  **/
	/**   x'04000000'  generate assembly listing without addresses            **/
	/**   x'08000000'  RNDSNGL machine dependent change for DG                **/
	/**   x'10000000'  Target dependent unused on pentium                     **/
	/**   x'20000000'  line profiling                                         **/
	/**   x'40000000'  leave external symbol names in mixed case              **/
	/**                                                                       **/
	/** Additionally, bits 12-15 give the architecture variant for which      **/
	/** backend optimisation should be performed                              **/
	/***************************************************************************/
	int archvariant;

	miscreport=options&0x1;
	setdbx=options&0x20000;
	globreport=options&0x4;
	bbschedule=options&0x1000000;
	asmlist=options&0x4000000;
	gschedule=options&0x100;
	leafopt=options&0x200;
	peepopt=options&0x400;
	archvariant=((unsigned)options>>12)&0xF;
	BSetArchVariant(archvariant);
	peepreport=globreport;
	hazardreport=globreport;
	ProcNum=0;
	firstentry=1;
}	/* sparc init       */
/***/
void p5reinit() {
	/*************************************************************************/
	/** For completeness but nouthing seems to be needed                    **/
	/*************************************************************************/
	ProcNum=0;
	firstentry=1;
}
/***/
void p5setpi(struct procfmt * tpi) {
	if (tpi->proclevel==2 && PI->proclevel==1)  outerPI=PI;
	PI=tpi;
}	/*p5 setPI*/
/***/
/***/
void puthex(int n,int d) {
	static const unsigned char hex [15+1] = {
		'0','1',
		'2','3','4','5','6','7',
		'8','9','A','B','C','D','E','F'
	};
	int i,j,k;
	j=0;
	if (d==0) {
		printf("0x"); 
		d=1;
	}
	for (i=7; i>=0; i--) {
		k=((unsigned)n>>(i<<2))&15;
		if (d>i)  j=1;
		if (k!=0) {
			printf("%c",hex [k]);
			j=1;
		} else if (j!=0) {
			printf("%c",hex [k]);
		}

	}
}	/*puthex*/
/***/
static void p5Error(char * ErrStr) {
	/* ****call on untranslateable imp support routine**** */;
	printf("\n***** P5 CODE OPTIMISER INTERNAL ERROR -\n");
	printf("      %s\n",ErrStr);
	exit(2);
}	/*p5 Error*/
/***/
/***/
void CPrintLine(int line,int prefix) {
	/*************************************************************************/
	/** Prints the given line number with the given line prefix             **/
	/*************************************************************************/
	struct LinePrefixFmt *LinePrefix;
	int prefixtable [50+1];
	int position,i;

	position=0;
	while (prefix!=0) {
		LinePrefix=(struct LinePrefixFmt*)(prefix);
		position++;
		prefixtable [position]=LinePrefix->line;
		prefix=LinePrefix->parent;
	}
	for (i=position; i>=1; i--) {
		printf("%1d:",prefixtable [i]);
	}
	printf("%1d",line);
}	/*CPrintLine*/
/***/
void Ccountparams(int *aparamprops,int sideentry) {
	/*************************************************************************/
	/** Examine the properties of the arguments of a procedure              **/
	/** declaration and set register management data as appropriate -       **/
	/** returns the number of registers containing an argument in low reg.  **/
	/** Also handles the transfer of incoming parameter FregVars in %I<n>   **/
	/** registers to their allocated %F<n> registers.                       **/
	/**                                                                     **/
	/** Structure of parameter info for C and C++ is as follows (One 32     **/
	/** bit word for each parameter):                                       **/
	/** Bits 28-31: The alignment of the parameter (1,2,4 or 8 bytes)       **/
	/** Bits 24-27: The type of the parameter                               **/
	/** Bit     23: Set if the parameter is a register parameter            **/
	/** Bit     22: Set if the parameter is not to be saved on entry        **/
	/** Bits 16-21: The logical number of any remapped register parameter,  **/
	/**             else 0                                                  **/
	/** Bits  0-15: The size of the parameter in bytes                      **/
	/**                                                                     **/
	/** Structure of parameter info for FORTRAN, PASCAL and MODULA is as    **/
	/** follows (One 32 bit word for each parameter):                       **/
	/** Bits 30-31: The alignment of the parameter                          **/
	/** Bits 24-29: The type of the parameter                               **/
	/** Bits 16-23: Set to 1 if the parameter is unused or used only in the **/
	/**             prologue                                                **/
	/** Bits  0-15: The size of the parameter in bytes                      **/
	/**                                                                     **/
	/** On RS6000 only record parameter information in a funny compact way  **/
	/** suitable for insertion into IBM's Tracebacktable produced at the    **/
	/** procedure end by "tidy frags". this info goes into the PI record    **/
	/** for storage until needed                                            **/
	/*************************************************************************/
	unsigned char StoreFlags [REGCEILING+1];
	int i,paramtype,PBase,paramprop;
	int hidden,elipsis,j,n;
	int TBTbits,nTbit,ipcnt,fpcnt,code	/* decs for IBM traceback*/;
#if (AllowReverseEndianData!=0 && Language==CCOMP && LanguageVariant==USLC)
	int paramlen,cumoffset;
#endif

	for (i=0; i<=REGPARAMNUM-1; i++) {
		StoreFlags [i]=0;
	}
	if (sideentry==0) {
		for (i=0; i<=256; i++)  StackSTflags [i]=0;

		for (i=0; i<=(((unsigned)Regparamsize>>2)-1); i++) {
			paramSTflags [i]=0;
			ParamSTMmarkers [i]=0;
		}
	}

	TBTbits=0;	 
	ipcnt=0;	 
	fpcnt=0;	 
	nTbit=31;
	elipsis=0;	 
	n=0;	 
	i=0;
	PI->inparsize=0;
	if (aparamprops!=NULL) {
		n=aparamprops[0];	/* no of param entries                          */
		i=aparamprops[1];	/* no of byte of params passed                */
		if (i<0)  elipsis=1;	/* variable no of params                                */
		if (i>=0) {
			PI->inparsize=i;
		} else {
			PI->inparsize=n<<2;
		}

		/* Set the register variable masks                                           */

#if((Language==CCOMP)&&(LanguageVariant==USLC)) 
		RegClaimMaskA=aparamprops[2];
		RegClaimMaskB=aparamprops[3];
		PBase=4;

#else
		RegClaimMaskA=0;
		RegClaimMaskB=0;
		PBase=2;

#endif;

	} else {
		RegClaimMaskA=0;
		RegClaimMaskB=0;
		/*         lowreg=0                                                          */
	}


	/**/
	/* Check for hidden parameters -- should be set in procprops but             */
	/*also check the table. Check can not be made if there is an elipsis. CCOMP  */
	/* must set the procprops bit                                                */
	/**/
	hidden=((unsigned)PI->procprops>>9)&1;
	if (hidden!=0)  PI->inparsize+=4;
	if (elipsis==0) {
		for (j=0; j<=n-1; j++) {
			paramprop=aparamprops[PBase+j];
			if (paramprop==-1)   continue ;
			paramtype=((unsigned)paramprop>>24)&15;
			if (paramtype==ResAddrval)  hidden=1;
			if (paramtype==Realval) {
				nTbit-=2;
				if ((paramprop&0xFFFF)==8)  code=3; 
				else code=2;
				fpcnt++;
				TBTbits|=code<<nTbit;
			} else {
				nTbit--;	/*code bit already zero                                            */
				ipcnt++;
			}
		}
	}

#if(Language==PASCAL) 
	PI->procprops|=(hidden<<9);
#endif;	/*  PASCAL is careless here                                          */
	PI->ipcnt=ipcnt;	 
	PI->fpcnt=fpcnt;
	/**/
	/* All params are store by ABI convention. There is mothing else to do       */
	/* except do byte swapping of wrong endian data that has arrived             */
	/**/
	/* fix by rtr: parameters have at least word size                            */
	/*             bytes do not need to be swapped                               */
	/*             halfwords need to be shifted after swapping                   */
	/**/

#if((AllowReverseEndianData!=0)&&(Language==CCOMP)&&(LanguageVariant==USLC)) 
	cumoffset=(4*hidden)+8;
	for (j=0; j<=n-1; j++) {
		paramprop=aparamprops[PBase+j];
		if (paramprop==-1) {
			cumoffset+=4;  
			continue ;
		}
		paramtype=((unsigned)paramprop>>24)&15;
		paramlen=paramprop&0xFFFF;
		/**/
		/* don't swap return addresses, */
		/* structure value parameters, and byte size params */
		if (paramtype!=ResAddrval && paramtype!=Structval && paramlen>1 && (paramprop&0x800000)!=0) 	/* swapping needed */{
			if (paramtype==Realval && paramlen>=12) {
				ARCH(floadri(FLDq,EBP,cumoffset,currentFSP-1);
				ARCH(fstoreri(FSTPd,currentFSP-1,EBP,cumoffset));
			}
			ARCH(loadri(LW,EBP,cumoffset,EAX));
			ARCH(opr(BSWAP,EAX));
			if (paramtype==Realval && paramlen>=8) {
				ARCH(loadri(LW,EBP,cumoffset+4,EDX));
				ARCH(opr(BSWAP,EDX));
				ARCH(storeri(ST,EAX,EBP,cumoffset+4));
				ARCH(storeri(ST,EDX,EBP,cumoffset));
			} else {
				if (paramlen==2)  ARCH(rlit(SAR,EAX,16,EAX));
				ARCH(storeri(ST,EAX,EBP,cumoffset));
			}
		}
		cumoffset+=(paramlen+3)&(-4);	/* bump to next mltpl of 4 */
	}

#endif;
}	/* Ccountparams     */
/***/
static void ProcessSparse() {
	/************************************************************************/
	/**  This deals with sparse switch tables.  It searches for fragments  **/
	/** containing a sparse switch table, and then replaces the instruction**/
	/** with a set of IF THEN GOTOs.                                       **/
	/** Assumptions made :                                                 **/
	/**      PI_ProcFrag points at the first fragment of the proc being    **/
	/**          processed                                                 **/
	/**      PI_curfrag points at the fragment into which new instructions **/
	/**          are placed.  This is assumed to be empty (ie last user    **/
	/**          has done an BBreakFrag)                                   **/
	/**      There is only one SWITCHTAB in a fragment, and it is the last **/
	/**          instruction (safe to assume as BBreakFrag was introduced  **/
	/**          into CSwitch)                                             **/
	/************************************************************************/
	struct fragfmt *CurrentFragment;	/* frag being processed */
	struct fragfmt *NextFragment;		/* the one after the Switch */
	struct fragfmt *FirstNewFragment,*LastNewFragment	/* where our new code goes */;
	struct fragfmt *EndFragment;		/* the last USED fragment in proc */
	struct fragfmt *EmptyFragment;		/* The new last empty Fragmentof proc */
	struct Swtabfmt *Tab;			/* the switch table itself */
	struct fragfmt * NextInList;		/* so we can cycle through whole */
						/* list even after altering links */
	int I,CaseLabel,CaseLabelx;

	CurrentFragment=PI->procfrag;
	while (CurrentFragment!=NULL) {
		NextInList=CurrentFragment->nextfrag;
		if (CurrentFragment->switchtab!=0) {
			Tab=(struct Swtabfmt*)(CurrentFragment->switchtab);
			if (Tab->Mode==SPARSESWITCH) {
				/* start to plant the IF THEN GOTOs for the sparse switch */
				CurrentFragment->switchtab=0;
				/**/
				FirstNewFragment=PI->curfrag;
				for (I=0; I<=Tab->SlotsUsed-1; I++) {
					CaseLabel=Tab->u0.S [I].Label;
					CaseLabelx=BLocateLabel(CaseLabel,0);
					if (I==(Tab->SlotsUsed-1)) 	/* Last case */{
						if (Tab->Rangelab>0) 	/* There is an error lab */{

							ARCH(rlit(CMP,RETURNREG,Tab->u0.S [I].Entry,RETURNREG));
							ARCH(bcctf(JE<<16,CaseLabelx,0))	/* otherwise we have */;
						} else {
							ARCH(bcctf(JMP<<16,CaseLabelx,0))	/* NO default unconditionally to last */;
						}
						/* a branch in a branch's */
					} else {
						ARCH(rlit(CMP,RETURNREG,Tab->u0.S [I].Entry,RETURNREG));
						ARCH(bcctf(JE<<16,CaseLabelx,0))	/* delay slot at the end */;
					}
					/* cycling through each case */
				}

				/* Now we have the GOTO default, reached only if no IF succeeds */
				if (Tab->Rangelab>0)  ARCH(bcc(JMP<<16,Tab->Rangelab,0));

				/* At this stage, the new instructions are at the end of the list */
				/* of fragments, so they have to be reordered */
				LastNewFragment=PI->curfrag;	/* where our new code ends */

				/* Now we have to make a new fragment for future code */
				if (Tab->Rangelab>0)  BTerminateFrag(Tab->Rangelab,0); 
				else BBreakFrag(0);

				/* first join the switch fragment with our new code */
				EndFragment=FirstNewFragment->prevfrag;
				NextFragment=CurrentFragment->nextfrag;
				CurrentFragment->nextfrag=FirstNewFragment;
				FirstNewFragment->prevfrag=CurrentFragment;

				/* now join the new code with that which followed the switch */
				LastNewFragment->nextfrag=NextFragment;
				NextFragment->prevfrag=LastNewFragment;

				/* and finally point the end of the code at the new empty fragment */
				EmptyFragment=PI->curfrag;		/* the new, empty fragment */
				EmptyFragment->prevfrag=EndFragment;
				EndFragment->nextfrag=PI->curfrag;
			}
		}
		CurrentFragment=NextInList;
	}	/* While CurrentFragment #  NULL */
}	/*ProcessSparse*/

static void deleteunusedstackstores() {
	/****************************************************************/
	/** remove the STore instruction of any stack location which   **/
	/** is not otherwise referenced                                **/
	/**   Bits signify as follows in StackSTflags                  **/
	/**   2**3 allocated as a temp                                 **/
	/**   2**2 has its address taken                               **/
	/**   2**1 is loaded                                           **/
	/**   2**0 is stored into                                      **/
	/****************************************************************/
	struct fragfmt *frag;
	struct instrfmt *instr;
	int i,adtaken;

	/* If the address is taken of any stack location then we cannot delete */
	adtaken=0;
	if ((PI->privprops&FRAMEADDRTAKEN)!=0)  adtaken=1; 
	else {
		for (i=0; i<=256; i++) {
			if ((StackSTflags [i]&0xC)==4)  adtaken=1;
		}
	}
	StackSTflags [0]=StackSTflags [0]|(adtaken<<2);	/* for recheck stack stores*/

	frag=PI->procfrag;

	while (frag!=NULL) 	/* through all frags in this procedure */{
		instr=frag->firstinstr;
		while (instr!=NULL) 	/*through all instructions in this frag*/{
			if (INTSTORE<=instr->group && instr->group<=FPSTORE) {
				if ((instr->privprops&FRAMEACCESS)!=0) {
					if (-1024<=instr->u0.offset && instr->u0.offset<0) {
						i=(unsigned)(-instr->u0.offset+3)>>2;
						if ((StackSTflags [i]==1 && adtaken==0) ||
							StackSTflags [i]==9/*temp $store*/) {
							if ((instr->datasize<=4 || StackSTflags [i-1]==StackSTflags [i]) &&
								instr->opcode!=FISTP && instr->opcode!=FSTPm &&
								instr->opcode!=FSTPd)  BDeleteInstr(instr,0);
							/*store is dead since it is never loaded or addressed*/
						}
					}
				}
			}

			instr=instr->nextinstr;
		}
		frag=frag->nextfrag;
	}
}	/* delete unused stack stores                                              */


static int tailparams(struct instrfmt *callinstr) {
	/*************************************************************************/
	/** callinstr is a recursive call. try and transfer parameters to input **/
	/** site to avoid a recursive call. We take a very cautious line and    **/
	/** give up on floats, parameters involing a call or on anything like   **/
	/** a local address being passed.                                       **/
	/** Particularly difficult is the case when an undefined reg is pushed  **/
	/** This may be a regvar containing a pointer to a local so must fail   **/
	/** returns 1 if done.   0 if unsafe to change the call                 **/
	/*************************************************************************/
	int creepoffset,state,ptr,pushedregs;
	static const int dangerregs=(1<<EAX)|(1<<EBX)|(1<<ECX)|(1<<EDX)|(1<<ESI)|(1<<EDI);
	struct instrfmt *iads [8+1];
	struct instrfmt *curinstr;

	creepoffset=0;	 
	ptr=0; pushedregs=0;
	if (PI->inparsize==0)  return 1;	/* No params at all */
	if (PI->inparsize>16) {
		state=1; 
		goto fail;
	}
	curinstr=BMachineInstr(callinstr->previnstr,PREVCHAIN);
	while (curinstr!=NULL) {
		if ((curinstr->props&ANYCALL)!=0) {
			state=2; 
			goto fail;
		}
		if (curinstr->opcode==LEA && (curinstr->privprops&FRAMEACCESS)!=0) {
			state=3; 
			goto fail;
		}
		if ((curinstr->rdef&(1<<ESP))!=0 && curinstr->opcode!=PUSH) {
			state=4; 
			goto fail;
		}
		if (curinstr->group==FPSTORE) {
			state=5; 
			goto fail;
		}
		if ((curinstr->props&(LOADINSTR|STOREINSTR))!=0 && curinstr->area==PARAMS && 
			(curinstr->u0.offset>=creepoffset || curinstr->u0.offset==-1)) {
			state=6; 
			goto fail;
		}
		if (curinstr->opcode==PUSH) {
			if (curinstr->variant!=OPPLUSR && curinstr->variant!=OPMEMLIT) {
				state=7; 
				goto fail;
			}
			if (curinstr->variant==OPPLUSR) pushedregs|=curinstr->rref;
			if ((curinstr->privprops&FIXEDLIT)!=0) {
				state=8; 
				goto fail;
			}
			iads [ptr]=curinstr;	 
			ptr++;
			creepoffset+=4;
		}
		pushedregs&=(~curinstr->rdef);
		if (creepoffset==PI->inparsize && 
			((pushedregs&dangerregs)==0 || (PI->privprops&FRAMEADDRTAKEN)==0))  goto cando;
		curinstr=BMachineInstr(curinstr->previnstr,PREVCHAIN);
	}
	state=10;	 
	goto fail;
cando:
	/* Now change the instrs                                                    */
	ptr--;
	while (ptr>=0) {
		curinstr=(struct instrfmt*)(iads [ptr]);
		if (curinstr->variant==OPPLUSR) 	/* PUSH reg => ST reg,x(%EBP)*/{
			curinstr->opcode=ST;
			curinstr->rs1=EBP;
			curinstr->disp=8+(ptr<<2);
			curinstr->group=INTSTORE;
			curinstr->props=STOREINSTR|DESTROYABLE;
			curinstr->area=PARAMS;
			curinstr->u0.offset=ptr<<2;
			curinstr->datasize=4;
			curinstr->rref=(256<<EBP)|(1<<curinstr->rd);
			curinstr->privprops=FRAMEACCESS;
			curinstr->csize=3;
			curinstr->variant=OPRMR;
			curinstr->rmbyte=0x40;	/* 8 bit disp */
			curinstr->rdef=0;
		} else if (curinstr->variant==OPMEMLIT) {	/* PUSH lit => mov LIT */
			curinstr->opcode=MOV;
			curinstr->rs1=EBP;
			curinstr->disp=8+(ptr<<2);
			curinstr->group=INTSTORE;
			curinstr->props=STOREINSTR|DESTROYABLE;
			curinstr->area=PARAMS;
			curinstr->u0.offset=ptr<<2;
			curinstr->datasize=4;
			curinstr->rref=256<<EBP;
			curinstr->privprops=FRAMEACCESS;
			curinstr->variant=OPMEMLIT;
			curinstr->datasize=4;
			curinstr->csize=7;
			curinstr->rmbyte=0x40;	/* 8 bit disp */
			curinstr->rdef=0;
		} else Mabort(628);

		ptr--;
	}
	return 1;
fail:

	if (optimtrace!=0&&peepreport!=0) {
		printf("Tail PARAM move fails state=%2d instrad = %.8X\n",state,(unsigned)curinstr);
	}
	return 0;
}	/* tail params */
/***/
static void tailrecursion() {
	/*************************************************************************/
	/** Looks for a call followed by a return or jump to return and         **/
	/** if the call is to the current procedure substitues a jump           **/
	/** to the special tail recursion label (PI_returnlab+2)                **/
	/** Abandon optimisation unless all params in registers                 **/
	/*************************************************************************/
	struct fragfmt *frag,*prevfrag;
	struct instrfmt *instr,*jinstr,*stinstr;
	int id,mode;

	id=-1;
	frag=PI->procfrag;
	if (frag->entryid!=0)  id=frag->entryid;
	while (frag->nextfrag!=NULL) {
		frag=frag->nextfrag;
		if ((frag->props&RETURNBRANCH)!=0 && frag->labrefinstr!=NULL) {
			jinstr=frag->labrefinstr;
			instr=BMachineInstr(jinstr->previnstr,PREVCHAIN);
			mode=0;
			if (instr==NULL && frag->prevfrag!=0) {
				prevfrag=frag->prevfrag;
				instr=BMachineInstr(prevfrag->lastinstr,PREVCHAIN);
				mode=1;
			}
			if (instr!=NULL && instr->opcode==ADD && instr->rd==ESP && instr->variant==OPRSLIT) {
				stinstr=instr;
				instr=BMachineInstr(stinstr->previnstr,PREVCHAIN);
			} else stinstr=NULL;
			if (instr!=NULL && (instr->privprops&DIRECTCALL)!=0 && instr->u1.immval==id && 
				(jinstr->props&BRANCH)!=0 && (jinstr->props&CONDITIONALBRANCH)==0) {
				if (tailparams(instr)!=0) {
					if (optimtrace!=0&&peepreport!=0) {
						printf("PHOLE: Tail recursion removed\n");
						p5printinstr(instr);
					}
					if (stinstr!=NULL)  BDeleteInstr(stinstr,0);
					if (mode==0) 	/* can overwrite jump */{
						BDeleteInstr(instr,0);
						jinstr->u1.immval=BLocateLabel((PI->returnlab+2)+PI->labadjust,0);
						frag->props=frag->props^RETURNBRANCH;
						frag->labref=jinstr->u1.immval;
					} else {
						instr->u1.immval=BLocateLabel((PI->returnlab+2)+PI->labadjust,0);
						prevfrag->labref=instr->u1.immval;
						prevfrag->labrefinstr=instr;
						instr->opcode=JMP;
						instr->group=instrgroup [JMP];
						instr->props=BRANCH;
						instr->privprops=0;
						instr->variant=OPPCREL;
						instr->csize=5;
						instr->rref=0;
						instr->cref=0;
						instr->fref=0;
						instr->rdef=0;
						instr->cdef=0;
						instr->fdef=0;
					}
				}
			}
		}
	}
}	/*Tail recursion*/
/***/
static int congruentfrags(struct fragfmt *frag1,struct fragfmt *frag2){
	/*
	*********************************************************************
	* Looks for two frags that are the same and end in an unconditional *
	* jump to the same place. Only looking for 'return TRUE' type stmst *
	* but could be made a lot more elaborate                            *
	*********************************************************************/
struct instrfmt * instr11,*instr12,*instr13,*instr21,*instr22,*instr23;

	if (frag1->labref==0 || frag2->labref==0 || frag1->labref!=frag2->labref) return 0;
	instr12=frag1->labrefinstr;
	instr11=BMachineInstr(instr12->previnstr,PREVCHAIN);
	instr13=BMachineInstr(instr12->nextinstr,NEXTCHAIN);
	instr22=frag2->labrefinstr;
	instr21=BMachineInstr(instr22->previnstr,PREVCHAIN);
	instr23=BMachineInstr(instr22->nextinstr,NEXTCHAIN);
	if (instr13!=NULL || instr23!=NULL) return 0;
	if (instr11==NULL || instr21==NULL) return 0;
	if ((instr12->props&(BRANCH|CONDITIONALBRANCH))!=BRANCH) return 0;
	if ((instr22->props&(BRANCH|CONDITIONALBRANCH))!=BRANCH) return 0;
	if (instr12->u1.immval!=instr22->u1.immval) return 0;
	if (instr11->opcode!=instr21->opcode || instr11->variant!=instr21->variant) return 0;
	if ((instr11->privprops&FIXEDLIT)!=(instr21->privprops&FIXEDLIT)) return 0;
	if ((instr11->privprops&FIXEDLIT) &&
		(instr11->area!=instr21->area || instr11->u0.offset!=instr21->u0.offset))
		return 0;
	if ( instr11->variant==OPPLUSRLIT && instr11->opcode==MOV &&
		instr11->rd==instr21->rd && instr11->u1.immval==instr21->u1.immval)
		return 1;
	return 0;
} /* congruentfrags* */

static struct fragfmt * tailmerge(struct fragfmt *frag1,struct fragfmt *frag2){
	/*
	******************************************************************
	* frag2 & frag1 are congruent. change frag2 to jump to frag1     *
	******************************************************************/

	struct instrfmt *instr,*instr1,*instr2;
	struct fragfmt *newfrag;
	int lab,labx;
	struct lrecfmt *lrec;

	/* had frag1 got more instructions than the common tail. If so
	   we need to insert another frag and move instructions        */
	instr1=frag1->labrefinstr;
	instr2=BMachineInstr(instr1->previnstr,PREVCHAIN);
	if (BMachineInstr(instr2->previnstr,PREVCHAIN)!=NULL) {
		newfrag=BInsertFrag(frag1->nextfrag);
		BMoveBefore(frag1,newfrag,instr2,NULL);
		newfrag->labrefinstr=instr1;
		frag1->labrefinstr=NULL;
		BMoveBefore(frag1,newfrag,instr1,NULL);
		newfrag->props=RETURNBRANCH;
		frag1->props&=(~RETURNBRANCH);
		 frag1->props|=COMMONTAIL;
		newfrag->labref=frag1->labref;
		frag1->labref=NULL;
	} else {
		newfrag=frag1;
	}

	if (newfrag->labindex==0) {
		lab=Mprivatelabel();
		labx=BLocateLabel(lab+PI->labadjust,0);
		lrec=BLabRecAd(labx);
		lrec->frag=newfrag;
	newfrag->labindex=labx;
	}
	labx=newfrag->labindex;
	frag2->labref=labx;
	instr=frag2->labrefinstr;
	instr->u1.immval=labx;
	frag2->props&=(~RETURNBRANCH);
	frag2->props|=COMMONTAIL;
	instr=BMachineInstr(instr->previnstr,PREVCHAIN);
	BDeleteInstr(instr,0);
	return newfrag;
} /*tailmerge */


static void commontails() {
	/*
	******************************************************************
	* Checks all return jump frag for simple commonality and coalesce*
	* into a single frag                                             *
	* must be done before frag reorganisation                        *
	******************************************************************/
	struct fragfmt *frag1,*frag2;

	frag1=PI->curfrag;
	while (frag1!=NULL) {
		if ((frag1->props&RETURNBRANCH)!=0) {
			frag2=frag1->prevfrag;
			while (frag2!=NULL) {
				if ((frag2->props&RETURNBRANCH)!=0) {
					if (congruentfrags(frag1,frag2))
						frag1=tailmerge(frag1,frag2);
				}
				frag2=frag2->prevfrag;
			}
		}
		frag1=frag1->prevfrag;
	}
} /* commontails */

void Cprocessproc() {
	/********************************************************************/
	/** process the current procedure and perform expansion of sparse  **/
	/** switches for C and C++                                         **/
	/********************************************************************/
	int traceproc;


	traceproc=BGetTraceProc();
	if (traceproc==0 || traceproc==ProcNum) {
		peepreport=globreport;
	} else {
		peepreport=0;
	}
	if (optimtrace!=0 && peepreport!=0) {
		BPrintFrags("PHOLE: FRAGMENTS BEFORE PROCESSING");
	}
	ProcessSparse();
	if (peepopt!=0)  tailrecursion();
	if (((Language==FORTRAN && LanguageVariant!=FORTRAN90) ||
		Language==CCOMP || (PI->procprops&PP_NOINTERNAL)!=0) && leafopt!=0) {
		/* for block strucutured procs we can not tell what is going on so do     */
		/* not attemp any deletions unless there are no inner blocks (props&32#0) */
		deleteunusedstackstores();
	}
	if (peepopt!=0)  commontails();
	if (optimtrace!=0 && peepreport!=0) {
		BPrintFrags("PHOLE: FRAGMENTS AFTER PROCESSING");
	}
	peepreport=globreport;
}	/* Cprocessproc     */
/***/
static struct instrfmt * followinginstr(struct fragfmt *frag,struct instrfmt * instrad) {
	/*************************************************************************/
	/** Gives the address of the instruction that executes after the one    **/
	/** at instrad. Chases into subsequent frags but not via jumps          **/
	/*************************************************************************/
	 struct instrfmt * i;
	struct fragfmt *nextfrag;
	i=BMachineInstr(instrad,NEXTCHAIN);
	if (i!=NULL || (frag->props&FALLSTHROUGH)==0 || frag->nextfrag==NULL)  return i;
	/**/
	nextfrag=frag;
	do 	/* chase through following frags */{
		nextfrag=nextfrag->nextfrag;
		nextfrag=nextfrag->final;
		i=BMachineInstr(nextfrag->firstinstr,NEXTCHAIN);
		if (i!=NULL || (nextfrag->props&FALLSTHROUGH)==0 || nextfrag->nextfrag==NULL)  return i;
	} while (1) /* FOR EVER */;
}	/*following instr */
/***/
static struct instrfmt * followinginstr2(int *fragaddr,struct instrfmt*instrad,int mode) {
	/*************************************************************************/
	/** Gives the address of the instruction that executes after the one    **/
	/** at instrad. Chases into subsequent frags but not via jumps          **/
	/** B reorganise fragmants may not have been called so that _props      **/
	/** will not be valid. Can test _final field for this condition         **/
	/** mode=0 continue to end or unconditional jump                        **/
	/** mode=1 dont continue past a label                                   **/
	/*************************************************************************/
	struct instrfmt * i;
	struct fragfmt *nextfrag,*frag;
	frag=(struct fragfmt*)(*fragaddr);
	i=BMachineInstr(instrad,NEXTCHAIN);
	if (i!=NULL || frag->nextfrag==0 || 
		((frag->props&FALLSTHROUGH)==0 && frag->final!=0))  return i;
	/**/
	nextfrag=frag;
	do 	/* chase through following frags */{
		*fragaddr=(int)nextfrag->nextfrag;
		nextfrag=(struct fragfmt*)(*fragaddr);
		if (nextfrag->labindex!=0 && mode!=0)  return 0;
		i=BMachineInstr(nextfrag->firstinstr,NEXTCHAIN);
		if (i!=NULL || nextfrag->nextfrag==0 || 
			((nextfrag->props&FALLSTHROUGH)==0 && nextfrag->final!=0 && 
			nextfrag->uses>0))  return i;
	} while (1) /* FOR EVER */;
}	/*following instr2 */
/***/
static struct fragfmt * followingfrag(struct fragfmt *frag,struct instrfmt *instrad) {
	/*************************************************************************/
	/** Gives the address of the fragment holding the instruction that      **/
	/** executes after the one at instrad. Chases into subsequent frags but **/
	/** not via jumps                                                       **/
	/*************************************************************************/
	struct instrfmt * i;
	struct fragfmt *nextfrag;
	i=BMachineInstr(instrad,NEXTCHAIN);
	if (i!=NULL || (frag->props&FALLSTHROUGH)==0 || frag->nextfrag==0)
		  return frag;
	/**/
	nextfrag=frag;
	do 	/* chase through following frags */{
		nextfrag=nextfrag->nextfrag;
		nextfrag=nextfrag->final;
		i=BMachineInstr(nextfrag->firstinstr,NEXTCHAIN);
		if (i!=NULL || (nextfrag->props&FALLSTHROUGH)==0 || nextfrag->nextfrag==0)
			  return nextfrag;
	} while (1) /* FOR EVER */;
}	/*following instr */
/***/
void Cestablishca(struct fragfmt *frag,int *ca) {
	/****************************************************************/
	/** process the current fragment and determine total code size **/
	/****************************************************************/
	int op;
	struct instrfmt *instr,*nextinstr;
	struct instrvariants *ivar;
	struct Exdatafmt *exdata;

#if (MINCODESIZE==0)
		if ((bbschedule|gschedule)!=0 && 
		  ((frag==frag->final && (frag->props&(FALLENINTO|DSWITCHCASEFRAG))==0) || frag->prevfrag==0)) {
			*ca=(*ca+15)&(-16);
		}
#endif
	frag->address=*ca;
	nextinstr=frag->firstinstr;
	while (nextinstr!=NULL) {
		instr=nextinstr;
		nextinstr=instr->nextinstr;
		op=instr->opcode;
		if (Pic==0 &&
		    (op==LW || op==ST || op==SB || op==LBNOX) &&
		    instr->rd==EAX &&
		    (instr->privprops&(FIXEDINSTR|SIBREQD|EXTENINSTRFORM))==FIXEDINSTR) {
			instr->csize--;
			instr->privprops|=EXTENINSTRFORM;
			if (optimtrace!=0 && peepreport!=0) {
				printf("ESTBLSH: Instruction shortened %08X\n",(unsigned)instr);
			}
		}
		if (instr->variant==OPRLIT && instr->rd==EAX) {
			ivar=(struct instrvariants*)(&instrops [instr->opcode*instrvarels]);
			if ((ivar->valid&opeaxlitval)!=0) {
				instr->variant=OPEAXLIT;
				instr->csize--;
				if (optimtrace!=0 && peepreport!=0) {
					printf("ESTBLSH: EAXLIT form used %.8X\n",(unsigned)instr);
				}
			}
		}
		if (instr->variant==OPBRMLIT && instr->rd==EAX) {
			ivar=(struct instrvariants*)(&instrops [instr->opcode*instrvarels]);
			if ((ivar->valid&opallitval)!=0) {
				instr->variant=OPALLIT;
				instr->csize--;
				if (optimtrace!=0 && peepreport!=0) {
					printf("ESTBLSH: ALLIT form used %.8X\n",(unsigned)instr);
				}
			}
		}
		/***/
		switch (instr->group) {

		default:
#if(Language!=PASCAL && Language!=MODULA) 
			Mabort(40);	/* Invalid instruction class */

#endif;
			/***/

		case BCC:
		case JUMPLINK:
			*ca+=instr->csize;
			if (instrform [instr->opcode]==JFORM && (instr->privprops&DIRECTCALL)!=0) {
				exdata=exrecad(instr->u1.immval);
				if (exdata->Ca<0) 	/* Entry as yet unknown*/{
#if (OutputASSEMBLER!=Positive)
					if (exdata->PutId<=0) {
						if (strcmp(exdata->Name,"")==0 || (exdata->flags&4)!=0) {
							exdata->PutId=pnextsymbol();
						} else {
							exdata->PutId=pxname(exdata->flags,exdata->Name);
							/* Reserve an id if referencing a private procedure which */
							/* will be declared later else generate an external reference */
							/* for all others                              */
						}
					}
#endif
				}
			}
			continue ;

		case Unimp:
			/* Store access groups                                                      */
		case INTLOAD:
		case FPLOAD:
		case INTSTORE:
		case FPSTORE:
		case RWMEM:
		case INTOPS:
		case INTOPSu:
			if ((instr->privprops&PROCADFIX)!=0) {
				exdata=exrecad(instr->u0.offset);	/*id in offset fixcode*/
				if (exdata->Ca<0 && exdata->PutId<=0) {

#if(OutputASSEMBLER!=Positive) 
					if (strcmp(exdata->Name,"")==0 || (exdata->flags&4)!=0) {
						exdata->PutId=pnextsymbol();
					} else {
						exdata->PutId=pxname(exdata->flags,exdata->Name);
						/* Reserve an id if referencing a private procedure which    */
						/* will be declared later else generate an external reference*/
						/* for all others                                            */
					}

#endif;
				}
			}

		case SHIFTS:
		case SPECREGrw:
		case FPOPS1:
		case FPOPS2:
		case FPCOMPARE:
		case HICODEFIX:
		case COPYASM:
		case STROP:
			*ca+=instr->csize;
			continue ;
			/***/

		case LINENUMBER:
		case MARKER:
		case LINEDEBUG:
		case DBXINFO:
		case FIXUPPOINT:
		case DSWITCHNOTE:
		case DELETED:
		case CXTCHANGE:
		case REGIONINFO:
			continue ;
			/***/
		}	/* end of case based on instr->group */
	}	/* end of while loop */

	if (frag->switchtab!=0) *ca=((*ca+3)&(-4)); /* word align */
}	/* Cestablishca     */
/***/
/**/
/* Copyright (c) 1993 Edinburgh Portable Compilers Ltd.  All Rights Reserved.*/
/**/
/***/
void p5abiinit(int *fixedca) {
}	/*p5 abiinit*/

static void addprefixes(unsigned char *actcode,struct instrfmt *instr) {
	/*************************************************************************/
	/** Prefixes (up to 4) go at the start of the instruction.              **/
	/*************************************************************************/
	int i,l;
	l=0;
	for (i=0; i<=3; i++) {
		if (instr->u2.prefixes [i]!=0) {
			l++;
			actcode [l]=instr->u2.prefixes [i];
		}
	}
	actcode [0]=l;
}	/*addprefixes*/
/***/
static void addopcode(unsigned char *actcode,int opcode) {
	/*************************************************************************/
	/** The opcode is 1 or 2 bytes and goes after the prefixes              **/
	/*************************************************************************/
	int l;
	l=actcode [0]+1;
	if ((opcode&0xFF00)!=0) {
		actcode [l]=(unsigned)opcode>>8; 
		l++;
	}
	actcode [l]=opcode;
	actcode [0]=l;
}	/*addopcode*/
/***/
static void adddisp(unsigned char *actcode,int disp,int size) {
	/*************************************************************************/
	/** Displacements are normally 1 or 4 bytes as determined by modrm      **/
	/** Some intsructions allow only one size of disp(eg call shl)          **/
	/** 2 byte displacements are possible in prefixed instructions          **/
	/** if size =0 this routine chooses between 1 & 4                       **/
	/*************************************************************************/
	int l,i;
	if (size>4)  p5Error("Strange Displacement/Literal");
	if (size==0) {
		if (disp<-128 || disp>127) {
			size=4;
		} else {
			size=1;
		}
	}
	l=actcode [0];
	for (i=0; i<=size-1; i++) {
		l++;
		actcode [l]=(unsigned)disp>>(8*i);
	}
	actcode [0]=l;
}	/*adddsip*/
/***/

static void addrmsubopreg(unsigned char *actcode,struct instrvariants *invar,int reg) {
	/*************************************************************************/
	/** Set up a rm byte with a subopcode and register                      **/
	/*************************************************************************/
	int l;
	l=actcode [0]+1;
	actcode [0]=l;
	actcode [l]=(0xC0|(invar->subop<<3))|reg;
}	/*addrmsubopreg */
/***/
static void addsibmem(unsigned char *actcode,struct instrfmt *instr,int mode,int midfield,int ca) {
	/*************************************************************************/
	/** Add an indexed memory refrence which may be fixed up                **/
	/*************************************************************************/
	int l,area;
	l=actcode [0]+2;
	actcode [0]=l;
	if ((instr->privprops&FIXEDINSTR)!=0) {
		if (instr->fixtype==GOTfix) {
			actcode [l-1]=0x84|(midfield<<3);	/* rm byte            */
			actcode [l]=((instr->sib&0xC0)|(instr->rs2<<3))|instr->rs1;
		} else {
			actcode [l-1]=4|(midfield<<3);		/* rm byte               */
			actcode [l]=((instr->sib&0xC0)|(instr->rs2<<3))|5;
		}
		adddisp(actcode,0,4);
#if (OutputASSEMBLER!=Positive)
		if (mode!=0) {
			area=instr->area;
			if (area>CNST)  area=egiveareaid(area);
			pfix2(CODE,ca+l,area,instr->u0.offset,instr->fixtype);
		}
#endif
	} else if (instr->disp==0 && instr->rs1!=EBP) {
		actcode [l-1]=(midfield<<3)|4;
		actcode [l]=((instr->sib&0xC0)|(instr->rs2<<3))|instr->rs1;
	} else if (instr->disp>=-128 && instr->disp<=127) {
		actcode [l-1]=(0x40|(midfield<<3))|4;
		actcode [l]=((instr->sib&0xC0)|(instr->rs2<<3))|instr->rs1;
		adddisp(actcode,instr->disp,1);
	} else {
		actcode [l-1]=(0x80|(midfield<<3))|4;
		actcode [l]=((instr->sib&0xC0)|(instr->rs2<<3))|instr->rs1;
		adddisp(actcode,instr->disp,4);
	}


}
/***/
static void addmem(unsigned char *actcode,struct instrfmt *instr,int mode,int midfield,int ca) {
	/*************************************************************************/
	/** Add a simple memory refrence which may be fixed up                  **/
	/*************************************************************************/
	int l,rm,dsize,area;
	if ((instr->privprops&SIBREQD)!=0) {
		addsibmem(actcode,instr,mode,midfield,ca); 
		return;
	}
	l=actcode [0]+1;
	actcode [0]=l;
	if ((instr->privprops&FIXEDINSTR)!=0) {
		actcode [l]=5|(midfield<<3);
		if ((instr->fixtype==GOTfix)||(instr->fixtype==GOTofffix))  actcode [l]=(EBX|(midfield<<3))|0x80;
		adddisp(actcode,0,4);
		area=instr->area;
		if (area>CNST)  area=egiveareaid(area);
#if (OutputASSEMBLER!=Positive)
		if (mode!=0)  pfix2(CODE,ca+l,area,instr->u0.offset,instr->fixtype);
#endif
		return;
	}
	if (instr->disp==0 && instr->rs1!=EBP) {
		rm=0;	 
		dsize=0;
	} else if (instr->disp>=-128 && instr->disp<=127) {
		rm=0x40;	 
		dsize=1;
	} else {
		rm=0x80;	 
		dsize=4;
	}

	actcode [l]=(rm|(midfield<<3))|instr->rs1;
	if (instr->rs1==ESP) 	/* Refs via sf are no slower */{
		actcode [l+1]=(4<<3)|ESP;	/* but need a sib byte       */
		actcode [0]=l+1;
	}
	if (dsize>0)  adddisp(actcode,instr->disp,dsize);
}	/*addmem */
/***/
static int Cgenerateinstr(int mode,struct instrfmt *instr,int ca,unsigned char *actcode) {
	/****************************************************************/
	/** process the current instruction and generate code          **/
	/** mode   = 0  form instruction only                          **/
	/**          1  form instruction and generate red tape         **/
	/** result = 0  no instruction generated                       **/
	/**          1  instruction generated (value in actcode)       **/
	/**          2  instruction generated (value in actcode)       **/
	/**             but there is more to come                      **/
	/** ca is the current address, updated if instr generated      **/
	/****************************************************************/
	struct lrecfmt *lrec;
	struct Exdatafmt *exdata;
	struct fragfmt *addrfrag;
	int form,tail,area,group,privprops,j,opcode,l,litsize;
	struct instrvariants *invar;
	opcode=instr->opcode;
	form=instrform [opcode];
	invar=(struct instrvariants*)((int)&instrops [opcode*instrvarels]);
	actcode [0]=0;
	group=instr->group;
	privprops=instr->privprops;
	if (group>=MINPSEUDOGROUP)  switch (group) {

	case LINENUMBER:
		latestlineno=instr->u1.immval;
#if (OutputASSEMBLER!=Positive)
		if (mode!=0 && setdbx!=0)  plinestart(latestlineno,ca);
#endif
		return 0;
		/***/

	case MARKER:
	case LINEDEBUG:
	case DSWITCHNOTE:
	case REGIONINFO:
	case DELETED:
	case COPYASM:
	case CXTCHANGE:
		return 0;

	case DBXINFO:
#if (OutputASSEMBLER!=Positive)
		if (mode!=0) {
			if (instr->opcode==0)  (*(int  *)(instr->u1.immval))=ca;	/*type 0 = give ca*/
			if (instr->opcode==1)  ppushfile();
			if (instr->opcode==2)  (*(int  *)(instr->u1.immval))=ppopfile();
		}
#endif
		return 0;
		/* fix area&offset to point here plus or minus immedval                     */
	case FIXUPPOINT:
#if (OutputASSEMBLER!=Positive)
		if (mode!=0) {
			pfix2(instr->area,instr->u0.offset,CODE,ca+instr->u1.immval,2);
		}
#endif
		return 0;
	default:
		BADSWITCH(group,__LINE__,__FILE__);
	}	/*end case for control operation not instruction*/
	addprefixes(actcode,instr);
	/***/
	if (form==NOFORM) {
		addopcode(actcode,invar->u0.onlyop);
		    if (instr->opcode==ENTER) {
			adddisp(actcode,(unsigned)instr->u1.immval>>8,2);
			    adddisp(actcode,instr->u1.immval&255,1);
		}
		if (instr->opcode==RETN) {
			adddisp(actcode,instr->u1.immval,2);
		}
		return 1;
	}
	if (form==JFORM) {		/* treat jumps by form not variant */
		if ((instr->props&ANYCALL)==0) 	/* pc rel jumps */{
			if ((privprops&KNOWNOFFSET)!=0) {
				tail=instr->u1.immval;
				    lastlocalcallra=ca+instr->csize;	/* Remeber for adjusting switches */
			} else {
				tail=0;
				    lrec=BLabRecAd(instr->u1.immval);
				    if ((int)lrec->frag!=0) {
					addrfrag=lrec->frag;
					if (addrfrag->final!=NULL) addrfrag=addrfrag->final;
					tail=addrfrag->address-(ca+instr->csize);	/*Base is next instr addr*/
				}
			}
			if (instr->csize<=2) {
				addopcode(actcode,invar->other	/* short form of jump here*/);
				    if (ca>0 && (tail<-128 || tail>127))  Mabort(960);
				    adddisp(actcode,tail,1);
				    return 1;
			}
			addopcode(actcode,invar->oppcrel	/* Long form of branch */);
			    adddisp(actcode,tail,4);
			    return 1;
		}
		/* If here it is a call                                                      */
		exdata=exrecad(instr->u1.immval);
		    addopcode(actcode,invar->oppcrel	/* Long form of call)*/);
		    /**/
		/* We can fill known calls here BUT in PIC mode Globals can exist in .so     */
		/* and in the a.out. The choice of which is made by the linker under         */
		/* control -Bsymbolic option. Can onl;y fill local calls in PIC mode         */
		/**/
		if (exdata->Ca>=0 && ((exdata->flags&4)!=0 || Pic==0)) 	/*known local routine*/{
			tail=exdata->Ca-(ca+5);	/*Base is next instr addr*/
			adddisp(actcode,tail,4);
			    return 1;
		}
		adddisp(actcode,0,4);
#if (OutputASSEMBLER!=Positive)
		if (mode!=0) {
			/**/
			/* id assigned by Cestablish ca                                              */
			/**/
			pfix2(CODE,ca+1,exdata->PutId,-4,dcallfix);	/* code relative branch fixup   */
		}
#endif
		return 1;

	}
	if (form==SLITFORM) {		/* treat shift-by-lit as a special */
		addopcode(actcode,invar->oprmslit);
		    if (instr->variant==OPRSLIT) 	/* There is a special for immval=1 currently ignored*/{

			addrmsubopreg(actcode,invar,instr->rd);
		} else {
			addmem(actcode,instr,mode,invar->subop,ca);
		}
		adddisp(actcode,instr->u1.immval,1);
		    return 1;

	}
	switch (instr->variant) {

	case OPONLY:
	case FOPONLY:
		addopcode(actcode,invar->u0.onlyop);
		    if (instr->opcode==ENTER) {
			adddisp(actcode,(unsigned)instr->u1.immval>>8,2);
			    adddisp(actcode,instr->u1.immval&255,1);
		}
		if (instr->opcode==RETN) {
			adddisp(actcode,instr->u1.immval,2);
		}
		return 1;

	    case FOPPLUSR:
		if ((instr->rs1<instr->rd)||(invar->opplusreg==0)) {
			printf("%6d %6d\n",instr->rd,instr->rs1);	 
			    p5Error("Funny float instr");
		}
		addopcode(actcode,(invar->opplusreg+instr->rs1)-instr->rd);
		    return 1;

	    case OPPLUSR:
		addopcode(actcode,invar->opplusreg+instr->rd);
		    return 1;

	    case OPR:
		addopcode(actcode,invar->oprm);
		    addrmsubopreg(actcode,invar,instr->rd);
		    return 1;

	    case OPRR:
		addopcode(actcode,invar->u0.oprrm);
		    l=actcode [0]+1;
		    actcode [0]=l;
		    actcode [l]=(0xC0|(instr->rd<<3))|instr->rs1;
		    return 1;

	    case OPRRM:
		if ((instr->privprops&EXTENINSTRFORM)!=0) {
			j=actcode [0]+1;
			    addmem(actcode,instr,mode,0,ca);
			    actcode [j]=invar->other;	/* overwite rm byte with special opcode */
			return 1;
		}
		addopcode(actcode,invar->u0.oprrm);
		    if ((instr->privprops&DSWITCHLOADINSTR)!=0) {
			tail=instr->disp;	/* May have to adjust disp due to aligning table */
			j=lastlocalcallra+instr->disp;	/* Is ca of table before alignmeny */
			j=(j+3)&(-4);	/* Now aligned */
			instr->disp=j-lastlocalcallra;	/* disp now adjusted */
			addmem(actcode,instr,mode,instr->rd,ca)	/* code planted */;
			    instr->disp=tail;	/* Back to original vale in case just monitoring*/
			/* However we may have altered instr size */
			/* All offsets should be within byte size */
			/* even allowing for max alignment (see Cswitch */
			/* but disp can become 0            */
			if ((mode==1)&&(instr->csize!=actcode [0])) {
				if (instr->csize>actcode [0]) {
					actcode [0]=actcode [0]+1;
					    actcode [actcode [0]]=0x90;	/* harmless NOP */
				} else Mabort(959);
			}
		} else addmem(actcode,instr,mode,instr->rd,ca);
		    return 1;

	    case OPRMR:
		if ((instr->privprops&EXTENINSTRFORM)!=0) {
			j=actcode [0]+1;
			    addmem(actcode,instr,mode,0,ca);
			    actcode [j]=invar->other;	/* overwite rm byte with special opcode */
			return 1;
		}
		addopcode(actcode,invar->oprmr);
		    addmem(actcode,instr,mode,instr->rd,ca);
		    return 1;

	    case OPRSLIT:
		addopcode(actcode,invar->oprmslit);
		    if (opcode==IMUL) {
			l=actcode [0]+1;
			    actcode [0]=l;
			    actcode [l]=(0xC0|(instr->rd<<3))|instr->rs1;
		} else addrmsubopreg(actcode,invar,instr->rd);
		    adddisp(actcode,instr->u1.immval,1);
		    return 1;

	    case OPBRMLIT:
		addopcode(actcode,invar->opbrmlit);
		    addrmsubopreg(actcode,invar,instr->rd);
		    adddisp(actcode,instr->u1.immval,1);
		    return 1;

	    case OPRLIT:
		addopcode(actcode,invar->oprmlit);
		    if (opcode==IMUL) {
			l=actcode [0]+1;
			    actcode [0]=l;
			    actcode [l]=(0xC0|(instr->rd<<3))|instr->rs1;
		} else addrmsubopreg(actcode,invar,instr->rd);
#if (OutputASSEMBLER!=Positive)
		if ( mode!=0 && (instr->privprops&FIXEDLIT)!=0) {
			area=instr->area;
			    if (area>CNST)  area=egiveareaid(area);
			    pfix2(CODE,ca+actcode [0],area,instr->u0.offset,instr->fixtype);
		}
#endif
		adddisp(actcode,instr->u1.immval,instr->datasize);
		    return 1;

	    case OPMEM:
	case FOPRM:
		addopcode(actcode,invar->oprm);
		    addmem(actcode,instr,mode,invar->subop,ca);
		    return 1;

	    case OPALLIT:
		addopcode(actcode,invar->allit);
		    adddisp(actcode,instr->u1.immval,1);
		    return 1;

	    case OPEAXLIT:
			if (instr->rd!=EAX) Mabort(958);
		addopcode(actcode,invar->eaxlit);
#if (OutputASSEMBLER!=Positive)
		if ( mode!=0 && (instr->privprops&FIXEDLIT)!=0) {
			area=instr->area;
			if (area>CNST)  area=egiveareaid(area);
			pfix2(CODE,ca+actcode [0],area,instr->u0.offset,instr->fixtype);
		}
#endif
		adddisp(actcode,instr->u1.immval,4);
		    return 1;

	    case OPBMEMLIT:
		addopcode(actcode,invar->other);
		    addmem(actcode,instr,mode,invar->subop,ca);
		    adddisp(actcode,instr->u1.immval,1);
		    return 1;

	    case OPMEMLIT:
		if ((instr->datasize==1) ||
		    (((invar->valid&oprmslitval)!=0) &&
		    ((-128<=instr->u1.immval)&&(instr->u1.immval<=127) &&
			((instr->privprops&FIXEDLIT)==0))))  litsize=1; 
		    else litsize=instr->datasize;
		    if (litsize==1)  addopcode(actcode,invar->oprmslit); 
		    else addopcode(actcode,invar->oprmlit);
		    if (opcode!=PUSH)  addmem(actcode,instr,mode,invar->subop,ca);
#if (OutputASSEMBLER!=Positive)
		if (mode!=0 && (instr->privprops&FIXEDLIT)!=0) {
			area=instr->area;
			if (area>CNST)  area=egiveareaid(area);
			pfix2(CODE,ca+actcode [0],area,instr->u0.offset,instr->fixtype);
		}
#endif
		adddisp(actcode,instr->u1.immval,litsize);
		    return 1;

	    case OPPLUSRLIT:
		addopcode(actcode,invar->opplusreg+instr->rd);
#if (OutputASSEMBLER!=Positive)
		if (mode!=0 && (instr->privprops&FIXEDLIT)!=0) {
			area=instr->area;
			if (area>CNST)  area=egiveareaid(area);
			pfix2(CODE,ca+actcode [0],area,instr->u0.offset,instr->fixtype);
		}
#endif
		adddisp(actcode,instr->u1.immval,4);	/* only mov */;
		    return 1;
		    /***/
	}	
	/* end of case on instr->variant */
	Mabort(878);
	return 0;
}	/* Cgenerateinstr   */
/***/
/**/
/* Copyright (c) 1993 Edinburgh Portable Compilers Ltd.  All Rights Reserved.*/
/**/
/***/
void Cgeneratefrag(struct fragfmt *frag) {
	/****************************************************************/
	/** process the current fragment and generate code             **/
	/****************************************************************/
	static unsigned char initseq [15+1] = {
		0xE8,0x0,0x0,0x0,0x0,		/* call  <procentry> */
		0x90,0x90,0x90,0x90,0x90,
		0x90,0x90,0x90,0x90,0x90,0x90};	/* Will be 16 byte aligned */
	static  unsigned char nops[16]= {0x90,0x90,0x90,0x90,0x90,
			0x90,0x90,0x90,0x90,0x90,
			0x90,0x90,0x90,0x90,0x90,0x90};
	static int next_code_byte=0;
	int ca,putprops,putid,tabentry,tabval,area,I,J,base;
	unsigned char p5code [32];
	char errmess [64];

	struct instrfmt *instr,*nextinstr;
	struct fragfmt *addrfrag;
	struct lrecfmt *lrec;
	struct Exdatafmt *exdata;
	struct Swtabfmt *tab;


#if(OutputASSEMBLER!=Positive) 
	buffptr=0;
	ca=frag->address;
	baseca=ca;
	if (ca!=next_code_byte) {
		pcbytes(next_code_byte,ca-next_code_byte,nops);
	}
	if (frag->entryid!=0) {
		exdata=exrecad(frag->entryid);
		exdata->Ca=ca;
		if ((exdata->Props&2)!=0) 	/*main entry*/{
			putprops=0x80000001;
		} else {
			putprops=exdata->Props&1;
		}
		if (exdata->PutId<=0)  putid=-1; 
		else putid=exdata->PutId;
		if (frag->prevfrag!=NULL) {
			putid=pentry2(putprops,ca,putid,exdata->Name);
		} else {
			pproc(exdata->Name,putprops,ca,&putid,latestlineno+1);
		}
		if (exdata->PutId<=0)  exdata->PutId=putid;
	}
	nextinstr=frag->firstinstr;
	while (nextinstr!=NULL) {
		instr=nextinstr;
		nextinstr=instr->nextinstr;
		do {
			I=Cgenerateinstr(1,instr,ca,&p5code[0] );
			if (I!=0) {
				if (p5code [0]!=instr->csize) {
					Cdisasfrag(frag);
					sprintf(errmess,"Generated instr size %s calc %d/gen %d",
						instrmnem [instr->opcode],instr->csize,p5code [0]);
					p5Error(errmess);
				}
				for (J=1; J<=(int)p5code [0]; J++) {
					codebuff [buffptr]=p5code [J];
					ca++;
					buffptr++;
					if (buffptr>1023) {
						pcbytes(baseca,1024,codebuff);
						buffptr=0;
						baseca=ca;
					}
				}
			}
			/*more info to generate for this pseudo-op*/
		} while (I>1) ;
	}
	if (frag->switchtab!=0) {
		tab=(struct Swtabfmt*)(frag->switchtab);
		while ((ca&3)!=0) 	/* align switch table */{
			codebuff [buffptr]=0x90;	/*NOP*/
			ca++;	 
			buffptr++;
		}
		for (tabentry=0; tabentry<=tab->Entries-1; tabentry++) {
			tabval=tab->u0.R [tabentry];
			if (tabval!=-1) {
				if (tabval<0) {
					p5Error("Illegal switch table entry");
				}
				lrec=BLabRecAd(tabval&0xFFFFFFF);
				addrfrag=lrec->frag;
				if (addrfrag->final!=NULL) addrfrag=addrfrag->final;
				if (Pic==0)  pfix2(CODE,ca,CODE,addrfrag->address,0)	/*non Pic to abs address*/;
			}
			if ((Pic==0)||(tabval==-1))  J=0; 
			else J=addrfrag->address-lastlocalcallra;
			codebuff [buffptr]=J;
			codebuff [buffptr+1]=(unsigned)J>>8;
			codebuff [buffptr+2]=(unsigned)J>>16;
			codebuff [buffptr+3]=(unsigned)J>>24;
			ca+=4;
			buffptr+=4;
			if (buffptr>1023) {
				pcbytes(baseca,buffptr,codebuff);
				buffptr=0;
				baseca=ca;
			}
		}
	}
	if (buffptr>0) {
		pcbytes(baseca,buffptr,codebuff);
	}
	next_code_byte=ca;
	if (frag->nextfrag==0 && PI->procfrag->entryid!=0) {
		pprocend(ca,PI->framesize,PI->saveareasize);
		area=((unsigned)PI->procprops>>11)&3;
		if (area!=0) 	/* This is .init or .fini proc */{
			base=pgivecurrentsize(area+10);
			if (base<0)  base=0;
			exdata=exrecad(PI->procfrag->entryid);
			pdbytes(area+10,base,16,initseq)	/* Code to init section */;
			pfix2(area+10,base+1,CODE,exdata->Ca-4,dcallfix)	/* Fix the call         */;
		}
	}

#endif;
}	/* Cgeneratefrag    */
/***/
int Cvalidatejumps(struct fragfmt *frag) {
	/*************************************************************************/
	/**    This routine is called after address have been assigned          **/
	/** Jumps can be shortened if the offset is 1 signed byte               **/
	/** This routine checks jumps and shortens if appropiate                **/
	/*************************************************************************/
	struct instrfmt *instr,*nextinstr;
	struct lrecfmt *lrec;
	struct fragfmt *tfrag;
	char S[32];
	int ca,count,j;
	unsigned reachable;

	ca=frag->address;		/*starting ca   */
	count=0;
	nextinstr=frag->firstinstr;
	while (nextinstr!=NULL) {
		instr=nextinstr;
		nextinstr=instr->nextinstr;
		if (instr->group==BCC && instr->opcode!=JMPPTR) {
			lrec=BLabRecAd(instr->u1.immval);
			if (lrec->frag==NULL) {
				 sprintf(S,"Unset Lab referenced %d",lrec->labnum-PI->labadjust);
				p5Error(S);
			}
			tfrag=lrec->frag;
			if (tfrag->final!=NULL) tfrag=tfrag->final;
			j=tfrag->address-(ca+2);	/* base is next instr address */
			reachable=(j>=-128 && j<=127);
			if (reachable && instr->csize>2 && (instr->privprops&OVERLONG)==0) {
				count++;
				instr->csize=2;
			}
			if ((!reachable) && instr->csize==2) {
				count++;
				instr->csize=6;
				if (instr->opcode==JMP) instr->csize=5;
				instr->privprops|=OVERLONG;	/* needed to prevent looping */
			}
		}
		if (instr->group<MINPSEUDOGROUP)  ca+=instr->csize;
	}
	return count;	/* count of overlong jumps                                    */
}	/*Cvalidate jumps   */
/***/
/**/
/* Copyright (c) 1993 Edinburgh Portable Compilers Ltd.  All Rights Reserved.*/
/**/
/***/
void Cdisasfrag(struct fragfmt *frag) {
	/****************************************************************/
	/** process the current fragment and list instructions         **/
	/****************************************************************/
	struct fragfmt *xfrag,*addrfrag,*tempfrag;
	struct instrfmt *instr,*tempinstr,*poststart,*previnstr,*nextinstr;
	struct lrecfmt *lrec;
	struct Swtabfmt *tab;
	struct Exdatafmt *exdata;
	int ca,tabval,val,area,i;

	/* print procedure start information for the first fragment */
#if (MINCODESIZE==0)
		if ((bbschedule|gschedule)!=0 && 
		   ((frag==frag->final && (frag->props&(FALLENINTO|DSWITCHCASEFRAG))==0 && frag->uses!=0) ||
			frag->prevfrag==0)) {
			printf("\t.text\n\t.align 16\n");
		}
#endif
	if (frag->entryid!=0) {
		if (firstentry!=0) printf("\nepctext:\n");
		if (frag->prevfrag==0) {
			printf("\n%s PROCEDURE: ",commentmark);
		} else {
			printf("\n%s ENTRY: ",commentmark);
		}
		exdata=exrecad(frag->entryid);
		printf("%s\n",exdata->Name);
		if (frag->prevfrag==0) {
#if OutputASSEMBLER==Positive
			int mask,fmask,i,offset;
			char name [256] ;
			strcpy(name,exdata->Name);
			if (strcmp(name,"s#go")==0)  strcpy(name,"MAIN_");
			if (name[0]=='s' && name[1]=='#') name[1]='_';
			printf("%c%c.text\n",HT,HT);
			if (firstentry!=0) firstentry=0;
			if ((PI->procprops&PP_EXTERNAL)!=0) printf("%c%c.globl      %s\n",HT,HT,name);
			printf("%s:\n",name);
#endif
		} else {
			firstentry=0;
		}

#if((Language==CCOMP)&&(LanguageVariant==USLC)&&(TargetABI==LynxOS)) 
		outputstabstrings();

#endif;
	}

	/* print any region structure information at the start of the fragment */
	ca=frag->address;
	previnstr=NULL;
	nextinstr=frag->firstinstr;
	if (nextinstr!=NULL && frag->labindex!=0) {
		instr=nextinstr;
		if (instr->group==REGIONINFO) {
			if (instr->previnstr!=0) {
				p5Error("Cdisasfrag: Bad instruction chain");
			}
			p5disasinstr(instr,&ca);
			previnstr=nextinstr;
			nextinstr=instr->nextinstr;
		}
	}
	poststart=frag->lastinstr;
	if (poststart!=NULL) {
		while (poststart!=NULL) {
			instr=poststart;
			if (instr->group!=REGIONINFO)   break ;
			poststart=instr->previnstr;
		}
		if (poststart==NULL) {
			poststart=instr;
		} else {
			poststart=instr->nextinstr;
		}
	}

	/* output any label associated with the start of the fragment */
	if (frag->labindex!=0) {
		lrec=BLabRecAd(frag->labindex);
		printf("\n");
		printf(".L%s:\t\t%s %x\n",itos(lrec->labnum),commentmark,frag->address);
	}

	/* disassemble the instructions in the fragment */
	while (nextinstr!=NULL && nextinstr!=poststart) {
		instr=nextinstr;
		if (instr->previnstr!=previnstr) {
			p5Error("Cdisasfrag: Bad instruction chain");
		}
		if (instr->group==LINENUMBER && instr->nextinstr!=0) {
			tempinstr=instr->nextinstr;
			if (tempinstr->group!=LINENUMBER) {
				p5disasinstr(instr,&ca);
			}
		} else {
			p5disasinstr(instr,&ca);
		}
		previnstr=nextinstr;
		nextinstr=instr->nextinstr;
	}

	/* allow assembler reorganisations again at the end of a user assembly */
	/* fragment                                                            */


	/* output any switch table associated with the fragment */
	if (frag->switchtab!=0) {
		tab=(struct Swtabfmt*)(frag->switchtab);
		if (tab->Mode==SPARSESWITCH)  p5Error("Unexpanded switch");
		printf("%c%c.align 4\n",HT,HT);
		printf(".SW%s:",itos(tab->Labbase));
		for (i=0; i<=tab->Entries-1; i++) {
			tabval=tab->u0.R [i];
			val=(unsigned)tabval>>28;
			if (val==1) {
				/* IMP switch                                                                */
				xfrag=(struct fragfmt*)(tabval&0xFFFFFFF);
				tabval=xfrag->address;
			} else {
				if (tabval!=-1) {
					if (tabval<0)  tabval=-tabval;
					lrec=BLabRecAd(tabval&0xFFFFFFF);
					addrfrag=lrec->frag;
					if (addrfrag->final!=NULL) addrfrag=addrfrag->final;
					tabval=addrfrag->address;
				}
			}
			printf("%c%c.long       ",HT,HT);
			if (val==1) {
				printf("X%08X",tabval);
			} else {
				printf(".L%s",itos(lrec->labnum));
				if (Pic!=0) {
					printf("-.Sbase%s+1 ",itos(tab->Labbase));
				}
			}
			printf("\n");
			ca+=4;
		}
	}

	/* output any region information pseudo instructions after any */
	/* dense switch information                                    */
	while (nextinstr!=NULL) {
		instr=nextinstr;
		if (instr->previnstr!=previnstr) {
			p5Error("Cdisasfrag: Bad instruction chain");
		}
		p5disasinstr(instr,&ca);
		previnstr=nextinstr;
		nextinstr=instr->nextinstr;
	}

	/* print information after the last fragment*/
#if (OutputASSEMBLER!=Positive)
	if (frag->nextfrag==0) {
		tempfrag=PI->procfrag;
		if (tempfrag->entryid!=0) {
			printf("\n");
		}
		area=((unsigned)PI->procprops>>11)&3;
		if (area!=0) 	/* This is .init or .fini proc */{
			xfrag=PI->procfrag;
			exdata=exrecad(xfrag->entryid);
			printf("%c%c",HT,HT);
			if (area==1) {
#if (TargetABI==DGUXABI) 
				printf(".section\t.init");
#else
				printf(".init");
#endif
			} else {
#if (TargetABI==DGUXABI) 
				printf(".section\t.fini");
#else
				printf(".fini");
#endif
			}
			printf("\n%c%ccall        %s\n%c%c.text\n",HT,HT,exdata->Name,HT,HT);
		}
	}
#endif

}	/*Cdisasfrag*/
/***/
void p5frlabel(int labx,int count,int curfragaddr) {
	/*************************************************************************/
	/**   The label whose index is labx has been used recently count times  **/
	/**   for a forward reference only. Obtain all registers defined since  **/
	/**   first use and clear their register memory. Better than clearing   **/
	/**   everything. Count normally one                                    **/
	/*************************************************************************/
	int gdef,cdef,fdef,i,j,g;

	struct instrfmt *instr;
	struct fragfmt *frag;

	gdef=0;	 
	cdef=0;	 
	fdef=0;
	frag=PI->curfrag;		/*Curfrag has only the label as yet    */
	frag=frag->prevfrag;
	while (frag!=NULL) {
		if (frag->labref==labx) {
			count--;
			if (count==0)  goto fragfound;
		}
		frag=frag->prevfrag;
	}
	Mabort(950);	/* Reach procstart without finding count jumps                 */
	/**/
fragfound:
	frag=frag->nextfrag;

	do {
		if (frag==NULL)   break ;
		instr=frag->firstinstr;
		while (instr!=NULL) {
			gdef|=instr->rdef;
			fdef|=instr->fdef;
			cdef|=instr->cdef;
			if ((instr->props&ANYCALL)!=0) {
				gdef|=~CALLEESAVEDREGS; 
				fdef|=~CALLEESAVEDFREGS;
			}
			g=instr->group;	/* can also define reguse by a store                        */
			if (g==INTSTORE)  gdef|=1<<instr->rd;
			if (g==FPSTORE)  fdef|=1<<(instr->rd&7);
			instr=instr->nextinstr;
		}
		frag=frag->nextfrag;
	} while (1) /* FOR EVER */;
	/**/
	for (i=0; i<=7; i++) {
		j=1<<i;
		if ((gdef&j)!=0)  forgetreg(i);
		if ((fdef&j)!=0)  forgetreg(i+8);
	}
}	/*p5 frlab*/


static void entrywrapper(struct fragfmt *frag,int imask,int fmask,int initoffset,int localsize,int rtl) {
	/*************************************************************************/
	/** Save the calle save registers on entry and set up the               **/
	/** real framepointer if we can not manage with a virtual one           **/
	/** Adjusting PI_curfrag to put the instructions in the                 **/
	/** correct sequence means there must be no breakfrags                  **/
	/*************************************************************************/
	int offset;
	struct fragfmt *savefrag;
	rclearregs(1);
	offset=initoffset;
	savefrag=PI->curfrag;
	PI->curfrag=frag;	/* There is a breakfrag in Mstart at right point */
	/**/
	if ((PI->proclevel<=1 && (PI->procprops&PP_NODISPLAY)!=0) || rtl>0 || 
		(PI->privprops&(CALLSINTERNAL|GLOBALACCESS))==0) 	/* Avoid enter with no display */{
		if (rtl==0) {
			ARCH(opr(PUSH,EBP));
			ARCH(modinstrprops(0,WRAPPERINSTR,0,0));
			ARCH(rr(MOV,ESP,-1,EBP));
			ARCH(modinstrprops(0,WRAPPERINSTR,0,0));
		}
		if ((rtl<=1)&&(localsize!=0)) {
			ARCH(oplit(SUB,ESP,localsize,ESP));
			ARCH(modinstrprops(0,WRAPPERINSTR|FRAMEMODIFY|BARRIERINSTR,0,0));
		}
	} else if (PI->proclevel==1) {		/* emulate an enter size,1 */
		ARCH(opr(PUSH,EBP));
		ARCH(modinstrprops(0,WRAPPERINSTR,0,0));
		ARCH(rr(MOV,ESP,-1,EBP));
		ARCH(modinstrprops(0,WRAPPERINSTR,0,0));
		ARCH(opr(PUSH,ESP))	/* Only component of display at level 1*/;
		ARCH(modinstrprops(0,WRAPPERINSTR,0,0));
		ARCH(oplit(SUB,ESP,localsize,ESP));
		ARCH(modinstrprops(0,WRAPPERINSTR|FRAMEMODIFY|BARRIERINSTR,0,0));
	} else {		/* use enter dealing with offsets > 12 bits specially */
		if (localsize<4095) {
			ARCH(enter(localsize,PI->proclevel));
			ARCH(modinstrprops(0,WRAPPERINSTR|FRAMEMODIFY|BARRIERINSTR,0,0));
		} else {
			ARCH(enter(localsize&0xFFF,PI->proclevel));
			ARCH(modinstrprops(0,WRAPPERINSTR,0,0));
			ARCH(rlit(SUB,ESP,((unsigned)localsize>>12)<<12,ESP));
			ARCH(modinstrprops(0,WRAPPERINSTR|FRAMEMODIFY|BARRIERINSTR,0,0));
		}
	};

	if ((imask&(1<<EDI))!=0) {
		ARCH(opr(PUSH,EDI));
		ARCH(modinstrprops(0,WRAPPERINSTR,0,0));
	}
	if ((imask&(1<<ESI))!=0) {
		ARCH(opr(PUSH,ESI));
		ARCH(modinstrprops(0,WRAPPERINSTR,0,0));
	}
	if ((imask&(1<<EBX))!=0) {
		ARCH(opr(PUSH,EBX));
		ARCH(modinstrprops(0,WRAPPERINSTR,0,0));
	}
	PI->curfrag=savefrag;
}	/*entry wrapper*/
/***/
static void exitwrapper(int imask,int fmask,int initoffset,int localsize,int rtl) {
	/*************************************************************************/
	/** Restore the callee saved registers on exit and reset STACKPOINTER   **/
	/*************************************************************************/
	struct fragfmt *frag;
	struct instrfmt *instr;
	int i,offset;

	frag=PI->curfrag;
	frag->props|=RETURNFRAG;	/*!NO COALESCE TAIL    pds sees no need to set this */
	rclearregs(1);
	if ((PI->proclevel<=1 && (PI->procprops&PP_NODISPLAY)!=0) || rtl>0 || 
		(PI->privprops&(CALLSINTERNAL|GLOBALACCESS))==0) 	/* Nodisplay */{
		offset=-localsize;
	} else {
		offset=(-localsize)-(4*PI->proclevel);
	}
	if ((imask&(1<<EDI))!=0)  offset-=4;
	if ((imask&(1<<EBX))!=0)  offset-=4;
	if ((imask&(1<<ESI))!=0)  offset-=4;
	/**/
	/* we have to restore EBX,ESI,EDI if used. It is best to use POP             */
	/* but this assumes ESP has been maintained correctly. If we load manually   */
	/* then we are not affected if we call old libraries that do no pop          */
	/* the structure result pointer as per the new (but not the old) ABI         */
	/* We are also proof against calls of alloca                                 */
	/**/
	if ((imask&(1<<EBX))!=0) {
		if (rtl!=0)  ARCH(opr(POP,EBX)); 
		else {
			ARCH(loadri(LW,EBP,offset,EBX));	 
			offset+=4;
		}
		ARCH(modinstrprops(0,WRAPPERINSTR,0,0));
	}
	if ((imask&(1<<ESI))!=0) {
		if (rtl!=0)  ARCH(opr(POP,ESI)); 
		else {
			ARCH(loadri(LW,EBP,offset,ESI));	 
			offset+=4;
		}
		ARCH(modinstrprops(0,WRAPPERINSTR,0,0));
	}
	if ((imask&(1<<EDI))!=0) {
		if (rtl!=0)  ARCH(opr(POP,EDI)); 
		else {
			ARCH(loadri(LW,EBP,offset,EDI));	 
			offset+=4;
		}
		ARCH(modinstrprops(0,WRAPPERINSTR,0,0));
	}
	/**/
	/* reset the stack pointer                                                   */
	/**/
	if (rtl==0) {

#if(MINCODESIZE!=0) 
		ARCH(oponly(LEAVE,(1<<ESP)|(1<<EBP),1<<EBP));
		ARCH(modinstrprops(0,WRAPPERINSTR,0,0));

#else
		/* The two instruction form of leave is faster with dual issue               */
		ARCH(rr(MOV,EBP,-1,ESP));
		/* the reset of SP must not migrate early leaving the frame exposed          */
		/* so pretend the instruction also defines EBP. It can not                   */
		/* then migrate in front of the last frame access                            */
		instr=BCurInstr();
		instr->rdef|=257<<EBP;
		instr->props|=WRAPPERINSTR;
		ARCH(opr(POP,EBP));
		ARCH(modinstrprops(0,WRAPPERINSTR|FRAMEMODIFY,0,0));

#endif;
	} else if (rtl==1) {
		ARCH(oplit(ADD,ESP,localsize,ESP));
		ARCH(modinstrprops(0,WRAPPERINSTR|FRAMEMODIFY,0,0));
	}

	i=0;
	if ((PI->privprops&RETURNSINT)!=0)  i=1<<EAX;
	 if ((PI->privprops&RETURNSLONG)!=0) i=(1<<EAX)|(1<<EDX);
	ARCH(oponly(RET,1<<ESP,(1<<ESP)|(1<<ESI)|(1<<EDI)|(1<<EBX)|i));
	ARCH(modinstrprops(0,WRAPPERINSTR|JUMPINSTR,0,0));
	if ((PI->procprops&PP_RETURNSAG)!=0) 	/* returns agregate*/{
		instr=BCurInstr();
		instr->opcode=RETN;	 
		instr->u1.immval=4;	 
		instr->csize=3;
	}
	if ((PI->procprops&PP_ALTCALLCONV) && PI->inparsize!=0) {
		instr=BCurInstr();
		instr->opcode=RETN;
		instr->u1.immval=PI->inparsize;
		instr->csize=3;
	}
}	/*exit wrapper*/
/***/
static void InvestigateGOTLoad() {
	/****************************************************************/
	/**  Chop GOTbase load at start of fn                          **/
	/****************************************************************/
	int cnt;
#define MAXGOTREGREFS 10
	struct fragfmt *frag;
	struct instrfmt *curinstr;
	struct instrfmt *iad [MAXGOTREGREFS+1];

	cnt=0;

	frag=PI->procfrag;
	while (frag!=NULL) {
		curinstr=frag->firstinstr;
		while (curinstr!=NULL) {
			if ((curinstr->rref|curinstr->rdef)&(1<<GOTREG)) {
				if (!((1<<GOTREG)&curinstr->rdef))  goto nogo;	/* genuine use found*/
				cnt++;
				if (cnt>MAXGOTREGREFS)  goto nogo;	/* too many side entries */
				iad [cnt]=curinstr;
			}

			curinstr=curinstr->nextinstr;
		}
		frag=frag->nextfrag;
	}
	for (cnt=cnt; cnt>=1; cnt--)  BDeleteInstr(iad [cnt],1);
	PI->rdef&=~(1<<GOTREG);
	if (optimtrace!=0 && peepreport!=0) {
		printf("PHOLE: GOT load deleted\n");
	}
	return;
nogo:

	if (optimtrace!=0 && peepreport!=0) {
		printf("PHOLE: GOT load delete fails after %4d Instrns\n",cnt);	 
		p5printinstr(curinstr);
	}
}	/*investgate GOT load*/

void p5dowrapping(int localsize,int cgoptions) {
	/*************************************************************************/
	/** Add the prologue and epilogue to the current procedure              **/
	/** Procedures with side entries(FORTRAN) need multiple prologues       ***/
	/** but share a common epilogue                                         **/
	/*************************************************************************/
	struct fragfmt *frag, *nextfrag;
	int imask,fmask,i,rtl,totsize;

	imask=PI->rdef&CALLEESAVEDREGS;
	fmask=PI->fdef&CALLEESAVEDFREGS;
	wrappediregs=imask;
	rtl=0;
	PI->saveareasize=0;
	for (i=0; i<=7; i++) {
		if ((1<<i)&imask)  PI->saveareasize+=4;
	}

	/* We want the adjustment in total to be a multiple of 8 bytes */
	totsize=localsize+PI->saveareasize+4*PI->proclevel;
	if ((PI->proclevel<=1 && (PI->procprops&PP_NODISPLAY)==0) ||
		(PI->privprops&(CALLSINTERNAL|GLOBALACCESS))==0)
		totsize-=4;
	if ((totsize&7)==4) {
		localsize+=4;
		PI->localsize=localsize;
	}

	/* perform leaf routine optimisation */

	if ((PI->privprops&(NOTLEAFRT|GLOBALACCESS))==0 && (PI->procprops&PP_HASSIDEE)==0 	/*no side entries*/
		 && leafopt!=0){
		rtl=DoLeafOpt(PI->procfrag);
	}
	wrappertype=rtl;	/* remember sort of wrappers used */
	if (rtl==0)  wrappediregs|=1<<EBP;

	entrywrapper(PI->procfrag,imask,fmask,PI->saveareasize,PI->localsize,rtl);

	if ((PI->procprops&PP_HASSIDEE)!=0) 	/* has side entries)*/{
		nextfrag=PI->procfrag;
		while (nextfrag!=NULL) {
			frag=nextfrag;
			if ((frag->entryid!=0)&&(frag->prevfrag!=0)) {
				entrywrapper(nextfrag,imask,fmask,PI->saveareasize,PI->localsize,rtl);
			}
			nextfrag=frag->nextfrag;
		}
	}
	/**/
	exitwrapper(imask,fmask,PI->saveareasize,PI->localsize,rtl);
}	/* p5 do wrapping*/
/***/

/***/
/***/
/********************************************************************************/
/**                                                                            **/
/**         Fragment cleanup                                                   **/
/**                                                                            **/
/********************************************************************************/


static void transform(unsigned char *reg,struct instrfmt *instr,int *regmap) {
	/*************************************************************************/
	/**    Chnages a single register reference to its new value             **/
	/*************************************************************************/
	int oldbit,newbit,newreg,oldreg;
	oldreg=*reg;	 
	newreg=regmap [oldreg];
	if (oldreg==newreg)  return;
	*reg=newreg;
	oldbit=1<<(oldreg&31);
	newbit=1<<(newreg&31);
	if (oldreg>f0REG) {
		Mabort(961);	/* can not transform fregs on stacked acc m-c*/
	} else {
		if ((oldbit&instr->rref)!=0)  instr->rref=(instr->rref&(~oldbit))|newbit;
		if ((oldbit<<8)&instr->rref)  instr->rref=(instr->rref&(~(oldbit<<8)))|(newbit<<8);
		if ((oldbit&instr->rdef)!=0)  instr->rdef=(instr->rdef&(~(oldbit|(oldbit<<8))))|(257<<newreg);
	}
	return;
}
/**/
void reintegrateregmasks(struct fragfmt *procfrag) {
	/*************************************************************************/
	/**    Revise the summary reguse masks in PI after optimisations        **/
	/*************************************************************************/
	struct fragfmt *frag,*nextfrag;
	struct instrfmt *instr,*nextinstr;
	int cdef,cref,rref,rdef,fref,fdef;
	int cdef1,cref1,rref1,rdef1,fref1,fdef1;
	cdef=0;	 cref=0;rdef=0;	 
	rref=0; fdef=0;	fref=0;
	/**/
	nextfrag=procfrag;
	while (nextfrag!=NULL) {
		frag=nextfrag;
		nextfrag=frag->nextfrag;
		nextinstr=frag->firstinstr;
		cdef1=0;	 
		cref1=0;
		rref1=0;	 
		rdef1=0;
		fref1=0;	 
		fdef1=0;
		while (nextinstr!=NULL) {
			instr=nextinstr;
			nextinstr=instr->nextinstr;
			if (instr->group<=MAXCODEGROUP) {
				cdef1|=instr->cdef;
				cref1|=instr->cref;
				rdef1|=instr->rdef;
				rref1|=instr->rref;
				fref1|=instr->fref;
				fdef1|=instr->fdef;
			}
		}
		frag->cuse=cref1; cref|=cref1;
		frag->cdef=cdef1; cdef|=cdef1;
		frag->ruse=rref1; rref|=rref1;
		frag->rdef=rdef1; rdef|=rdef1;
		frag->fuse=fref1; fref|=fref1;
		frag->fdef=fdef1; fdef|=fdef1;
	}
	PI->cdef=cdef;	 
	PI->cref=cref;
	PI->rdef=rdef;	 
	PI->rref=rref;
	PI->fdef=fdef;	 
	PI->fref=fref;
}
/***/
static int DoLeafOpt(struct fragfmt * procfrag) {
	/*************************************************************************/
	/** This procedure attempts to remove the stack frame allocation of a   **/
	/** leaf procedure. We do this by counting the references to SF         **/
	/** Result signifies as follows:-                                       **/
	/**       =0 no changes made                                            **/
	/**       =1 REfs changes to ESP frame still needed but not EBP         **/
	/**       =2 Routine  runs with ESP unchanged                           **/
	/*************************************************************************/
	struct instrfmt *curinstr;
	struct fragfmt *frag,*nextfrag;
	int adj,pcount,fcount,origdisp;

#if(MINCODESIZE!=0) 
	static const int SENSIBLE=5;

#else
	static const int SENSIBLE=12;	/* ESP refs are bigger so dont optimise*/

#endif;
	fcount=0;
	pcount=0;
	nextfrag=procfrag;
	while (nextfrag!=NULL) {
		frag=nextfrag;
		nextfrag=frag->nextfrag;
		curinstr=BMachineInstr(frag->firstinstr,NEXTCHAIN);
		while (curinstr!=NULL) {
			if ((curinstr->rdef&(1<<ESP))!=0)  return 0;	/* Changes ESP*/
			if ((curinstr->privprops&FRAMEACCESS)!=0) {
				if (curinstr->disp<0)  fcount++;
				if (curinstr->disp>0)  pcount++;
			}
			curinstr=BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
		}
	}
	if (targetvariant==0 && (fcount+pcount)>SENSIBLE)  return 0;
	if (fcount==0)  PI->localsize=0;	/* No frame reqd*/
	adj=PI->localsize+PI->saveareasize;
	nextfrag=procfrag;
	while (nextfrag!=NULL) {
		frag=nextfrag;
		nextfrag=frag->nextfrag;
		curinstr=frag->firstinstr;
		while (curinstr!=NULL) {
			if ((curinstr->privprops&FRAMEACCESS)!=0) {
				origdisp=curinstr->disp;
				if (curinstr->disp>0)  curinstr->disp+=adj-4;
				if (curinstr->disp<0)  curinstr->disp+=adj;
				if ((-128<=origdisp && origdisp<=127)&& 
					!(((-128<=curinstr->disp)&&(curinstr->disp<=127))))
					 curinstr->csize+=3;
				if ((-128<=curinstr->disp && curinstr->disp<=127) &&
					!((-128<=origdisp && origdisp<=127)))
					curinstr->csize-=3;
				if ((curinstr->privprops&SIBREQD)==0)  curinstr->csize++;
				if (curinstr->disp==0) {
					if (adj<=128)  curinstr->csize--; 
					else curinstr->csize-=3;	/* can happen */
				}
				curinstr->rs1=STACKPOINTER;
				curinstr->rref=(curinstr->rref&(~(257<<FRAMEPOINTER)))|(256<<STACKPOINTER);
			}
			curinstr=curinstr->nextinstr;
		}
	}
	if (fcount==0)  return 2;
	return 1;
}	/*DoLeafOpt*/
/***/
static void improveleafentry() {
	/*************************************************************************/
	/** Check out a type 1 leaf routine to see if the stack frame is still   */
	/** needed. If not delete it otherwise try the optimisations for a       */
	/** normal routine entry amended as necessary                            */
	/*************************************************************************/
	struct fragfmt *frag;
	struct instrfmt *instr,*subinstr,*addinstr,*nextinstr;
#define FVOLS (3<<7)
#define VOLS ((1<<EAX)|(1<<EDX)|(1<<ECX))
	int reffed,deffed,fdeffed,freffed,stkaccess,framesize;

	deffed=0;	 
	reffed=0;
	fdeffed=0;	 
	freffed=0;
	subinstr=NULL;	 
	addinstr=NULL;	 
	stkaccess=0;
	frag=PI->procfrag;
	while (frag!=NULL) {
		nextinstr=BMachineInstr(frag->firstinstr,NEXTCHAIN);
		while (nextinstr!=NULL) {
			instr=nextinstr;
			nextinstr=BMachineInstr(instr->nextinstr,NEXTCHAIN);
			if ((instr->props&WRAPPERINSTR)!=0) {
				if (instr->opcode==SUB && instr->rd==ESP && 
					(instr->variant==OPRLIT || instr->variant==OPRSLIT)) {
					framesize=instr->u1.immval;
					if (subinstr!=NULL)  return;
					subinstr=instr;
				}
				if (instr->opcode==ADD && instr->rd==ESP && 
					(instr->variant==OPRLIT || instr->variant==OPRSLIT)) {
					if (addinstr!=NULL)  return;
					addinstr=instr;
				}
			}
			if ((instr->props&(LOADINSTR|STOREINSTR))!=0) {
				if (instr->area==STACK || 
					(instr->rs1==ESP && instr->disp<framesize))  stkaccess=1;
			}
			if (instr->opcode==LEA && (instr->rref&(257<<ESP))!=0) {
				if (!(instr->rs1==ESP && (instr->privprops&SIBREQD)==0 && 
					instr->disp>framesize))  stkaccess=1;	/* addr of params only*/
			}
		}
		frag=frag->nextfrag;
	}
	if (stkaccess==0 && subinstr!=NULL && addinstr!=NULL) {
		if (addinstr->u1.immval!=framesize) {
			BPrintFrags("At point of failure");
			Mabort(982);
		}
		BDeleteInstr(subinstr,0);
		BDeleteInstr(addinstr,0);
		frag=PI->procfrag;
		while (frag!=NULL) {
			nextinstr=BMachineInstr(frag->firstinstr,NEXTCHAIN);
			while (nextinstr!=NULL) {
				instr=nextinstr;
				nextinstr=BMachineInstr(instr->nextinstr,NEXTCHAIN);
				if ((instr->props&(LOADINSTR|STOREINSTR))!=0 || instr->opcode==LEA) 	/* unsafe LEAs excluded above*/{
					if (instr->rs1==ESP) {
						instr->disp-=framesize;
						if (instr->disp<127 && (instr->disp+framesize)>127)
							instr->csize-=3;
					}
				}
			}
			frag=frag->nextfrag;
		}
		if (optimtrace!=0 && peepreport!=0) {
			printf("Leaf routine improved further");	 
			printf("\n");
		}
		return;
	}
#undef VOLS
#undef FVOLS
}	/*improve leafentry*/
/***/
static void improveprocentry() {
	/*************************************************************************/
	/** Attempt to move parameter loads in front of frame generation        **/
	/** this avoides the AGIs and gives the scheduler more scope            **/
	/*************************************************************************/
	struct fragfmt *frag;
	struct instrfmt *instr,*nextinstr;
	static const int FVOLS=3<<7;
	static const int VOLS=((1<<EAX)|(1<<EDX))|(1<<ECX);
	int reffed,deffed,fdeffed,freffed;

	deffed=0;	 
	reffed=0;
	fdeffed=0;	 
	freffed=0;
	frag=PI->procfrag;
	nextinstr=BMachineInstr(frag->firstinstr,NEXTCHAIN);
	while (nextinstr!=NULL) {
		instr=nextinstr;
		nextinstr=BMachineInstr(instr->nextinstr,NEXTCHAIN);
		if ((instr->props&LOADINSTR)!=0 && instr->area==PARAMS && 
			(instr->variant==OPRRM || instr->variant==FOPRM) && instr->rs1==EBP && 
			(instr->rdef&deffed)==0 && (instr->fdef&fdeffed)==0 && 
			((instr->rdef&VOLS)!=0 || (instr->fdef&FVOLS)!=0)) {
			BMoveAfter(frag,frag,instr,NULL);
			instr->csize++;
			instr->disp-=4;		/* push ebp not done */
			instr->rref=(instr->rref&(~(257<<EBP)))|(256<<ESP);
			instr->rs1=ESP;
			if (optimtrace!=0 && peepreport!=0) {
				printf("Param hoisted at procentry\n");
			}
		}
		if ((instr->props&STOREINSTR)!=0 && instr->area!=STACK)  return;
		deffed|=instr->rdef;
		reffed|=instr->rref;
		fdeffed|=instr->fdef;
		freffed|=instr->fref;
		if ((deffed&VOLS)==VOLS && freffed!=0)  return;
	}
}	/*improve procentry*/
/***/
static void improvereturns(struct fragfmt *jumpfrag,struct fragfmt *retfrag,struct instrfmt *retinstr
) {
	/*************************************************************************/
	/** Jumpfrag is marked as a retun junmp and retfrag is the destintn     **/
	/** which has at most 2 instructions. Copy the return over the jump     **/
	/** with some care as delay slots have been filled                      **/
	/*************************************************************************/
	struct instrfmt *jumpinstr;

	jumpinstr=(struct instrfmt*)(jumpfrag->labrefinstr);	/* Should be jump to return */
	if (optimtrace!=0 && peepreport!=0) {
		printf("PHOLE: improve return %08X %08X %3d %5d\n",(unsigned)jumpfrag,(unsigned)retfrag,
			jumpfrag->labref,retfrag->labindex);		 
	}
	if (!((jumpfrag->labref==retfrag->labindex && retfrag->labindex!=0) && 
		jumpinstr!=NULL && (jumpinstr->props&(BRANCH|CONDITIONALBRANCH))==BRANCH))  return;
	BCopyInstr(retinstr,jumpinstr)	/* Overwrite jump with first ret instr */;
	do {
		retinstr=BMachineInstr(retinstr->nextinstr,NEXTCHAIN);
		if (retinstr==NULL) {
			BUpdateLiveRegs(jumpfrag);
			return;
		}
		jumpinstr=BInsertInstr(jumpfrag,NULL)	/* at end */;
		BCopyInstr(retinstr,jumpinstr);
	} while (1) /* FOR EVER */;
}
/***/
/***/
/***/
void FinalTidy(struct fragfmt *procfrag) {
	/**************************************************************************/
	/** do procedure tidy-ups which must be performed late in the cycle      **/
	/**************************************************************************/
	struct fragfmt *f,*frag,*prevfrag,*retfrag,*nextfrag,*targetfrag;
	struct instrfmt *instr,*lastinstr,*specinstr,*curinstr;
	struct lrecfmt *lrec;
	int rlive,flive,clive,alive;
	static const int fmask=~(1<<FLAGREG);

	retfrag=NULL;
	f=procfrag;
	while (f!=NULL) {
		frag=f;
		f=frag->nextfrag;
		if ((frag->props&RETURNFRAG)!=0)  retfrag=frag;
		curinstr=BMachineInstr(frag->firstinstr,NEXTCHAIN);
		while (curinstr!=NULL) 	/* regroup certain special pairs not scheduled correctly */{
			instr=curinstr;
			curinstr=BMachineInstr(instr->nextinstr,NEXTCHAIN);
			if (curinstr!=NULL&& targetvariant==0 && 
				((instr->issueprops&curinstr->issueprops)&TPIGSTART)!=0) {
				if ((instr->opcode==POP || instr->opcode==PUSH) &&
				    curinstr->opcode==instr->opcode)
					curinstr->issueprops&=~TPIGSTART;
				if ((curinstr->props&CONDITIONALBRANCH)!=0 &&
				    (instr->opcode==CMP || instr->opcode==CMPB || instr->opcode==TEST))
					curinstr->issueprops&=~TPIGSTART;
			}


#if (MINCODESIZE!=0)
			if ((instr->variant==OPRLIT || instr->variant==OPEAXLIT) &&
			    instr->rd<=3) {
				if (((instr->u1.immval&0xFFFF00FF)==0 && 
				    (instr->opcode==OR || instr->opcode==XOR || instr->opcode==TEST)) ||
					(instr->opcode==AND && (instr->u1.immval&0xFFFF00FF)==0xFFFF00FF)) {
					instr->rd|=4;
					instr->u1.immval=((unsigned)instr->u1.immval>>8)&0xff;
					instr->csize=3;
					instr->variant=OPBRMLIT;
					if (optimtrace!=0 && peepreport!=0) {
						printf("FINAL: AH type form used %08x\n",instr);
					}
				} else if ((instr->u1.immval&0xFFFF00FF)==0xff && instr->opcode==AND) {
					lastinstr=BMachineInstr(instr->previnstr,PREVCHAIN);
					do {
						if (lastinstr==NULL) break;
						if ((lastinstr->rdef&instr->rdef)!=0) break;
						lastinstr=BMachineInstr(lastinstr->previnstr,PREVCHAIN);
					} while(1);
					if (lastinstr!=NULL && lastinstr->opcode==LHU &&
						lastinstr->rd==instr->rd) {
						instr->rd|=4;
						instr->u1.immval=((unsigned)instr->u1.immval>>8)&0xff;
						instr->csize=3; instr->variant=OPBRMLIT;
						if (optimtrace!=0 && peepreport!=0) {
							printf("FINAL: AH type form used %08x\n",instr);
						}
					}
				}

			}
#endif
		}
	}

	if (retfrag==NULL)  goto specexec;
	instr=BMachineInstr(retfrag->firstinstr,NEXTCHAIN);
	if (instr==NULL)  goto specexec;
again:

	/**/
	/* if we have a simple return with fall thro then the stack reclaim          */
	/* after the previous call can probably be reclaimed                         */
	/**/
	if (!((instr->opcode==RET) ||
	    ((instr->opcode==MOV || instr->opcode==ADD) && instr->rdef==(1<<ESP))))  goto specexec;
	if ((retfrag->props&FALLENINTO)!=0 && (PI->privprops&NOTLEAFRT)!=0) {
		prevfrag=retfrag->prevfrag;
		while (prevfrag->lastinstr==NULL)  prevfrag=prevfrag->prevfrag;
		lastinstr=prevfrag->lastinstr;
		while (((((lastinstr->rref|lastinstr->rdef)&(257<<ESP)))==0) &&
		    ((lastinstr->props&((ANYCALL|JUMPINSTR)|BRANCH))==0) &&
		    (lastinstr->previnstr!=0))  lastinstr=lastinstr->previnstr;
		if ((lastinstr->privprops&PARAMRECLAIM)!=0) {
			BDeleteInstr(lastinstr,1);
			goto again;
		}
	}
	/**/
	f=procfrag;
	while ((f!=NULL)) {
		frag=f;
		f=frag->nextfrag;
		if (MINCODESIZE==0 && (frag->props&RETURNBRANCH)!=0) {
			improvereturns(frag,retfrag,instr);
		}
	}

	/**/
	/* Since we have no GIS try a little speculative instruction execution       */
	/* we look for a frag ending in a conditional jump where th next frag        */
	/* has no label. We then try to hoist an instruction from this frag into     */
	/* a bubble before the conditional jump. The optimisation is important       */
	/* because of the delays in fomp...bcc etc                                   */
	/* The hoisted instruction must not alter store or define anything           */
	/* that is live on entry to the jump target frag                             */
	/**/
specexec:

	f=procfrag;
roundagain:

	while ((f!=NULL)) {
		frag=f->final;
		f=frag->nextfrag;
		if (frag->labref==0 ||
		    frag->labrefinstr==0 ||
		    (frag->props&(FALLSTHROUGH|USERASSEMFRAG))!=FALLSTHROUGH)   continue ;
		nextfrag=f->final;
		if (nextfrag->uses!=1 || (nextfrag->props&FALLENINTO)==0 || 
			(nextfrag->props&USERASSEMFRAG)==0)   continue ;
		instr=BMachineInstr(frag->lastinstr,PREVCHAIN);
		if (instr->group!=BCC || instr->opcode==JMPPTR)   continue ;

		lrec=BLabRecAd(frag->labref);
		targetfrag=lrec->frag->final;
		specinstr=BMachineInstr(nextfrag->firstinstr,NEXTCHAIN);
		if (specinstr==NULL || (specinstr->privprops&SLOWRESULTINSTR)!=0)   continue ;
		if (specinstr->fdef!=0 || (specinstr->rdef&targetfrag->rin)!=0 || 
		    (specinstr->cdef&targetfrag->cin)!=0 || 
		    (specinstr->props&(STOREINSTR|BRANCH|CONDITIONALBRANCH|JUMPINSTR|ANYCALL))!=0 ||
		    ((specinstr->props&LOADINSTR)!=0 && (specinstr->area|specinstr->u0.offset)==-1))   continue ;
		if ((specinstr->cdef&(1<<FLAGREG))!=0) {
			BLiveSetAfterInstr(nextfrag,specinstr,&rlive,&flive,&clive,&alive);
			if ((clive&(1<<FLAGREG))!=0)   continue ;
		}
		while (instr!=NULL) {
			if (((specinstr->rdef&instr->rref)!=0) ||
			    (((specinstr->cdef&instr->cref)&fmask)!=0) ||
			    ((specinstr->rref&instr->rdef)!=0) ||
			    (((specinstr->cref&instr->cdef)&fmask)!=0))   break ;
			if ((instr->props&(ANYCALL|JUMPINSTR|WRAPPERINSTR))!=0)   break ;
			if (((specinstr->props&LOADINSTR)!=0) &&
			    ((instr->props&STOREINSTR)!=0) &&
			    (p5memoryoverlap(instr,specinstr,0)!=MONO))   break ;
			if (instr->bubbles<=1 || instr->bubbles==255) {
				instr=BMachineInstr(instr->previnstr,PREVCHAIN);
				continue ;
			}
			if ((specinstr->cdef&(1<<FLAGREG))!=0) {
				lastinstr=BMachineInstr(instr->previnstr,PREVCHAIN);
				if (lastinstr==NULL)   break ;
				BLiveSetAfterInstr(frag,lastinstr,&rlive,&flive,&clive,&alive);
				if (((clive&(1<<FLAGREG))!=0)||(lastinstr->opcode==FSTSW)) {
					instr=lastinstr;
					continue ;
				}	/* Best earlier here*/
			}
			instr->bubbles--;
			BMoveBefore(nextfrag,frag,specinstr,instr);
			instr->bubbles--;
			specinstr->issueprops|=TPCONTSPEC;
			BUpdateLiveRegs(nextfrag);
			BUpdateLiveRegs(frag);
			if (optimtrace!=0 && peepreport!=0) {
				printf("PHOLE: Instr executed speculatively %.8X\n",(unsigned)specinstr);
			}
			f=frag;
			goto roundagain;
		}
	}
}	/*FinalTidy*/


/***/

/***/
static void improvecompares(struct fragfmt *frag) {
	/*************************************************************************/
	/** Inspects fragments ending with a compare and branch. If the operands**/
	/** are bytes or halfs then try to amend the comparision to avoid costly**/
	/** sign extension. Other improvements may be possible                  **/
	/** This routine must be called before 'cleanup frag' to which it       **/
	/** logically belongs. The caller must ensure there is a labrefinstr    **/
	/*************************************************************************/
	int reg1,reg2,l1op,l2op,cmpop,jop,rlive,flive,clive,alive,state;
	struct instrfmt *jinstr,*cmpinstr,*l1instr,*l2instr,*iinstr;

	jinstr=frag->labrefinstr;
	if (jinstr==NULL)  return;
	jop=jinstr->opcode;
	cmpinstr=BMachineInstr(jinstr->previnstr,PREVCHAIN);
	if (cmpinstr==NULL)  return;
	cmpop=cmpinstr->opcode;
	if (cmpop!=CMP || cmpinstr->variant!=OPRR) {
		state=1; 
		goto fail;
	}
	l2instr=BMachineInstr(cmpinstr->previnstr,PREVCHAIN);
	if (l2instr==NULL) {
		state=2; 
		goto fail;
	}
	l2op=l2instr->opcode;
	if ((l2instr->props&LOADINSTR)==0 || (l2instr->rdef&cmpinstr->rref)==0) {
		state=3; 
		goto fail;
	}	/* wrong load */
	l1instr=BMachineInstr(l2instr->previnstr,PREVCHAIN);
	if (l1instr==NULL) {
		state=4; 
		goto fail;
	}
	l1op=l1instr->opcode;
	/**/
	/* there may be a base of index load between the two relevant loads          */
	/* check for this and skip it if it is harmless                              */
	/**/
	if ((l1instr->rdef&cmpinstr->rref)==0) {
		iinstr=l1instr;				/* Hang onto intermediate load */
		l1instr=BMachineInstr(l1instr->previnstr,PREVCHAIN);
		if (l1instr==NULL) {
			state=5; 
			goto fail;
		}
		l1op=l1instr->opcode;
		if ((l1instr->rdef&iinstr->rref)!=0) {
			state=6; 
			goto fail;
		}	/* interactions !*/
	}
	reg1=l1instr->rd;	 
	reg2=l2instr->rd;
	if (l1op==l2op && (l1op==LB || l1op==LBU) && reg1<=3 && reg2<=3 && reg1!=reg2 &&
		cmpinstr->rref==((1<<reg1)|(1<<reg2)) &&
		 (l1instr->rdef&l2instr->rref)==0) 	/*opnd also used as index !*/ {
		if (l1op==LB &&
			(cmpop==JA || cmpop==JAE || cmpop==JB || cmpop==JBE)) {
			state=7; 
			goto fail;
		}
		BLiveSetAfterInstr(frag,cmpinstr,&rlive,&flive,&clive,&alive);
		if (l1op==LBU) {
			if (jop==JGE)  jop=JAE;
			if (jop==JG)  jop=JA;
			if (jop==JLE)  jop=JBE;
			if (jop==JL)  jop=JB;
		}
		if ((l1instr->rdef&rlive)==0) {
			l1instr->opcode=LBNOX;
			l1instr->privprops|=BYTEREGOP;
			l1instr->csize--;
		}
		if ((l2instr->rdef&rlive)==0) {
			l2instr->opcode=LBNOX;
			l2instr->privprops|=BYTEREGOP;
			l2instr->csize--;
		}

		jinstr->opcode=jop;
		cmpinstr->opcode=CMPB;
		cmpinstr->privprops|=BYTEREGOP;

		if (optimtrace!=0 && peepreport!=0) {
			printf("\nImprove CMP: Sign Extn avoided at %08X\n",(unsigned)cmpinstr);
		}
		return;
	}
	state=8;
fail:

	if (optimtrace!=0 && peepreport!=0) {
		printf("\nImprove CMP: Exit state=%4d\n",state);	 
	}
}
/***/
static void improvereclaims(struct fragfmt *frag) {
	/*************************************************************************/
	/** Look for parameter space reclaims and attempt to merge them         **/
	/** or substitute faster sequences. Suitable (ie non nested) instrs     **/
	/** have been marked already by routine ccall.                          **/
	/*************************************************************************/
	struct fragfmt *nextfrag;
	int reg,rlive,flive,clive,alive,lindex,size;
	struct Exdatafmt *exdata;
	struct instrfmt *instr,*master,*previnstr;
	char x [256] ,y [256] ;

	previnstr=NULL;
	master=BMachineInstr(frag->lastinstr,PREVCHAIN);
	do {
		if (master==NULL)  return;
		if ((master->privprops&PARAMRECLAIM)!=0 && master->opcode==ADD && 
			master->rd==ESP)  goto found;
		if (master->opcode==MOV && master->rd==ESP && master->rs1==EBP && 
			(master->props&WRAPPERINSTR)!=0)  goto found;
		previnstr=master;
		master=BMachineInstr(master->previnstr,PREVCHAIN);
	} while (1) /* FOR EVER */;
found:

	/**/
	/* alloca is a naughty routine which tampers with the stackpointer           */
	/* check for calls before proceding further with this optimisation           */
	/**/
	instr=BMachineInstr(master->previnstr,PREVCHAIN);
	while (instr!=NULL) {
		if ((instr->props&ANYCALL)!=0 && (instr->privprops&KNOWNOFFSET)==0) {
			exdata=exrecad(instr->u1.immval);
			/* the use of imp_resolve handles all cases of underscores */
			if (imp_resolve(exdata->Name,x,"alloca",y)==0)  goto popopt;
		}
		instr=BMachineInstr(instr->previnstr,PREVCHAIN);
	}
	instr=BMachineInstr(master->previnstr,PREVCHAIN);
	while (instr!=NULL) {
		if (instr->opcode==ADD && instr->rd==ESP) {
			if ((instr->privprops&PARAMRECLAIM)==0)  goto popopt;	/* Other stack operation found*/
			if (master->opcode==ADD)  master->u1.immval+=instr->u1.immval;
			if (optimtrace!=0 && peepreport!=0) {
				printf("\nParam reclaim deleted at %08X\n",(unsigned)instr);
			}
			BDeleteInstr(instr,0)	/* Mark as deleted */;
		}
		instr=BMachineInstr(instr->previnstr,PREVCHAIN);
	}
	if (master->variant==OPRSLIT && master->u1.immval>=128) {
		/* instruction now needs a larger literal value    */
		master->variant=OPRLIT;	 
		master->datasize=4;
		master->csize+=3;
	}

	nextfrag=frag;
	lindex=BLocateLabel(PI->returnlab+PI->labadjust,0);

	while ((nextfrag->props&(RETURNFRAG|RETURNBRANCH|COMMONTAIL))==0 &&
		nextfrag->nextfrag!=0 && (nextfrag->props&FALLSTHROUGH)!=0 &&
		(nextfrag->labrefinstr==0 || nextfrag->labref==lindex)) {
		nextfrag=nextfrag->nextfrag->final;
	}
	if ((nextfrag->props&(RETURNFRAG|RETURNBRANCH|COMMONTAIL))!=0 &&
		(master->props&WRAPPERINSTR)==0) {
		BDeleteInstr(master,0);
		if (optimtrace!=0 && peepreport!=0) {
			printf("\nFinal Param reclaim deleted at %08X\n",(unsigned)master);
		}
		return;
	}
popopt:

	size=master->u1.immval;
	if (master->opcode==ADD &&
		(size==4 ||
		(size==8 && (MINCODESIZE!=0 || targetvariant==0)))) 	/* Change to pop */{
		reg=EDX;
		BLiveSetAfterInstr(frag,master,&rlive,&flive,&clive,&alive);
		if ( size==4 && previnstr!=NULL && (previnstr->rdef&(1<<EDX))!=0)  reg=ECX;
		if ((rlive&(1<<EDX))!=0) reg=ECX;
		master->opcode=POP;
		master->group=instrgroup [POP];
		master->rd=reg;
		master->datasize=4;
		master->csize=1;
		master->variant=OPPLUSR;
		master->rdef=(257<<ESP)|(257<<reg);
		master->rref=1<<ESP;
		master->props|=LOADINSTR;
		master->cdef=0;
		if (size==8 ) 		{
			instr=BInsertInstr(frag,master);
			BCopyInstr(master,instr);
			instr->rd=ECX;
			instr->rdef=(257<<ESP)|(257<<ECX);
		}
	}
}	/*improve reclaims*/
/***/
static void ImproveCondEstablish(struct fragfmt *frag) {
	/***************************************************************************/
	/** Searches for conditional establishment code which loads a 0 or 1 into **/
	/** a register depending on the result of a test or compare and           **/
	/** collapses it into a single SET                                        **/
	/** We allow two constructions. One where the then & else routes rejoin   **/
	/** on the fragment after the else (postfrag). The other where both the   **/
	/** then and else frags jump to the same point (usually RETURNLAB)        **/
	/***************************************************************************/
	struct fragfmt *thenfrag,*elsefrag,*postfrag;
	struct instrfmt *branchinstr,*estinstrA,*estinstrB,*postestinstr,*uncondinstr;
	struct lrecfmt *lrec;
	struct preddescfmt *preddesc,*tempdesc;
	int branchop,value,prevpred,nextpred;

	if (frag->labref==0 || frag->labrefinstr==0 || (frag->props&FALLSTHROUGH)==0 || 
	    (frag->props&USERASSEMFRAG)==0)  return;
	branchinstr=frag->labrefinstr;
	branchop=branchinstr->opcode;
	if (branchinstr->group!=BCC || frag->nextfrag==NULL)  return;
	thenfrag=frag->nextfrag;
	thenfrag=thenfrag->final;
	if (thenfrag->preds!=0 || thenfrag->uses!=1 || (thenfrag->props&FALLENINTO)==0 ||
	    (thenfrag->props&FALLSTHROUGH)!=0 || (thenfrag->props&USERASSEMFRAG)!=0 || 
	    BMachineInstr(thenfrag->firstinstr,NEXTCHAIN)==NULL) return;
	estinstrA=BMachineInstr(thenfrag->firstinstr,NEXTCHAIN);
	if (BMachineInstr(estinstrA->nextinstr,NEXTCHAIN)==NULL) return;
	if (estinstrA->variant!=OPPLUSRLIT || estinstrA->rd>3) return;
	if (estinstrA->u1.immval!=0 && estinstrA->u1.immval!=1) return;
	if (estinstrA->opcode!=MOV) return;
	value=estinstrA->u1.immval;
	uncondinstr=BMachineInstr(estinstrA->nextinstr,NEXTCHAIN);
	if ((uncondinstr->group!=BCC) || (uncondinstr->opcode!=JMP) || 
	    (thenfrag->labref==0) || (thenfrag->labrefinstr!=uncondinstr) ||
	    (thenfrag->nextfrag==0)) return;
	elsefrag=thenfrag->nextfrag;
	elsefrag=elsefrag->final;
	lrec=BLabRecAd(frag->labref);
	if (lrec->frag==elsefrag && BMachineInstr(elsefrag->firstinstr,NEXTCHAIN)!=NULL &&
	    (elsefrag->props&FALLENINTO)==0 && (elsefrag->props&USERASSEMFRAG)==0 &&
	    (elsefrag->uses==1)) {
		estinstrB=BMachineInstr(elsefrag->firstinstr,NEXTCHAIN);
		postestinstr=BMachineInstr(estinstrB->nextinstr,NEXTCHAIN);
		if (estinstrB->variant==OPPLUSRLIT && estinstrB->rd==estinstrA->rd && 
			estinstrB->opcode==MOV && estinstrB->u1.immval==(1-value)) {
			lrec=BLabRecAd(thenfrag->labref);
			if (postestinstr==NULL && (elsefrag->props&FALLSTHROUGH)!=0 && elsefrag->nextfrag!=NULL) {
				postfrag=elsefrag->nextfrag;
			} else postfrag=lrec->frag;
			postfrag=postfrag->final;
			if (postestinstr==NULL && lrec->frag==postfrag && (postfrag->props&FALLENINTO)!=0) {
				if (peepreport!=0) {
					printf("IMPROVING LOGICAL ESTABLISH AT %08X\n",(unsigned)frag);
				}
				thenfrag->labref=0;
				thenfrag->labrefinstr=0;
				thenfrag->props|=FALLSTHROUGH;
				elsefrag->props|=FALLENINTO;
				elsefrag->preds=0;
				elsefrag->labindex=0;
				frag->labref=0;
				frag->labrefinstr=0;
				postfrag->uses--;
				if (postfrag->uses<=1 && (postfrag->props&FALLENINTO)!=0)
					 postfrag->labindex=0;
				/**/
				/* now overwrite the jump of the then frag with the correct SETcc */
				/* and remove other jumps 				        */
				/**/
				if (value!=0)  branchop=InverseJump [branchop-(JO)];
				uncondinstr->opcode=setjump [branchop-(JO)];
				uncondinstr->group=INTOPSu;
				uncondinstr->rs1=0;
				uncondinstr->variant=OPR;
				uncondinstr->rd=estinstrA->rd;
				uncondinstr->u1.immval=0;
				uncondinstr->rref=1<<uncondinstr->rd;
				uncondinstr->rdef=257<<uncondinstr->rd;
				uncondinstr->cref=1<<FLAGREG;
				uncondinstr->props=DESTROYABLE;
				uncondinstr->privprops=BYTEREGOP;
				uncondinstr->csize=3;
				uncondinstr->rmbyte=0xC0;
				if ((((1<<uncondinstr->rd)&RegClaimMaskA))!=0) {
					uncondinstr->privprops|=REGVARASSN;
				}
				BDeleteInstr(branchinstr,1);
				prevpred=0;
				nextpred=postfrag->preds;
				while (nextpred!=0) {
					preddesc=(struct preddescfmt*)(nextpred);
					if (preddesc->frag==(int)thenfrag) {
						if (prevpred==0) {
							postfrag->preds=preddesc->next;
						} else {
							tempdesc=(struct preddescfmt*)(prevpred);
							tempdesc->next=preddesc->next;
						}
					}
					prevpred=nextpred;
					nextpred=preddesc->next;
				}
				BDeleteInstr(estinstrB,1);
				BReconvergeLiveness();   /* Updates not good enough here (learnt the hard way)*/
			}
		}
	}
}	/*ImproveCondEstablish*/
/***/
/***/
static void DelRedunCompares(struct fragfmt *frag) {
	/*******************************************************************************/
	/** Finds repeated compare operations and deletes the second, redundant,      **/
	/** compare                                                                   **/
	/*******************************************************************************/
	struct instrfmt *instr,*sinstr;

	if ((frag->props&FALLSTHROUGH)==0 || frag->nextfrag==NULL || frag->labref==NULL ||
		frag->labrefinstr==NULL)  return;
	instr=frag->labrefinstr;
	if (instr->rdef!=0)  return;
	instr=BMachineInstr(instr->previnstr,PREVCHAIN);
	if (instr==NULL)  return;
	if (instr->opcode!=CMP && instr->opcode!=CMPB)  return;
	if ((instr->privprops&(FIXEDINSTR|FIXEDLIT))!=0)  return;
	frag=frag->nextfrag;
	frag=frag->final;
	if (frag->labindex!=0 || frag->uses!=1)  return;
	sinstr=BMachineInstr(frag->firstinstr,NEXTCHAIN);
	if (sinstr==NULL)  return;
	if (sinstr->opcode!=CMP && sinstr->opcode!=CMPB)  return;
	if ((sinstr->privprops&(FIXEDINSTR|FIXEDLIT))!=0)  return;
	if (instr->opcode==sinstr->opcode && instr->variant==sinstr->variant && 
		instr->u1.immval==sinstr->u1.immval && instr->rd==sinstr->rd && instr->rs1==sinstr->rs1) {
		if (!(instr->variant==OPRR || instr->variant==OPRRM || instr->variant==OPRMR ||
			instr->variant==OPRLIT || instr->variant==OPRSLIT))  return;
		if (instr->variant==OPRRM || instr->variant==OPRMR) {
			if (instr->datasize!=sinstr->datasize)  return;
			if (p5memoryoverlap(instr,sinstr,1)!=MOEXACT)  return;
		}
		BDeleteInstr(sinstr,0);
		BUpdateLiveRegs(frag);
		if (optimtrace!=0 && peepreport!=0) {
			printf("DELETED REDUNDANT COMPARE INSTR AT %08X\n",(unsigned)sinstr);
		}
	}
}	/*DelRedunCompares*/
/***/
static void increasedataoffsetby(struct instrfmt *instr,int amount) {
	/*
	*******************************************************************
	* We are increasing the data offset by not more than 8 bytes      *
	* however even a small changes can change the size of the offsets *
	* past one of the critical thresholds. Hence need this RT to do it*
	*******************************************************************/
	int prev,new;

	prev=instr->disp;
	new=prev+amount;
	instr->u0.offset+=amount;
	if (instr->privprops&FIXEDINSTR) return;
	if (prev==0) {
		instr->csize++; instr->disp=new;
	} else if (prev<=127 && new>127) {
		instr->disp=new; instr->csize+=3;
	} else if (prev<-128 && new >=-128) {
		instr->disp=new; instr->csize-=3;
	} else if (new==0) {
		instr->disp=0; instr->csize--;
	} else instr->disp=new;
}
static void Cleanupfrag(struct fragfmt *frag,int final) {
	/****************************************************************/
	/** perform peepholing cleanups within frag                    **/
	/** Some optimisations are left to the final pass as they      **/
	/** can intefere with other peep hole routines                 **/
	/****************************************************************/
	int curi,previ,op,prevop,group;
	int FirstPass,changes,anychanged,changed,rlive,flive,clive,alive,
		rdef,rref,j,rd,rs1,fragaddr,anyref;
	struct instrfmt* fpads [21];
	struct instrfmt *curinstr,*previnstr,*nextinstr,*thirdinstr;

again:
	changes=0;
	curi=(int)BMachineInstr(frag->firstinstr,NEXTCHAIN);
	FirstPass=1;
	while (curi!=0) {
		curinstr=(struct instrfmt*)(curi);
		op=curinstr->opcode;
		group=curinstr->group;
		previ=(int)BMachineInstr(curinstr->previnstr,PREVCHAIN);
		previnstr=(struct instrfmt*)(previ);
		if (previ!=0) {
			prevop=previnstr->opcode;
		}


		/* Look for TEST register instructions that are redundant since */
		/* the previous instruction which defined the register also set */
		/* the flags register in a STANDARD way                         */
		if (op==TEST && curinstr->variant==OPRR && curinstr->rd==curinstr->rs1 && 
			 previ!=0) {
			while (((previnstr->rdef&curinstr->rref)==0) &&
				((previnstr->cdef&(1<<FLAGREG))==0)&&((previnstr->props&ANYCALL)==0)) {
				previ=(int)BMachineInstr(previnstr->previnstr,PREVCHAIN);
				if (previ==0)   break ;
				previnstr=(struct instrfmt*)(previ);
			}
			if (previnstr!=NULL) prevop=previnstr->opcode;
			if (((previnstr->rdef&255/*alphas only*/)==curinstr->rref) &&
				((previnstr->cdef&(1<<FLAGREG))!=0)) {
				if ((instrsideeffects [prevop]&2/*STND*/)!=0) {
					if (optimtrace!=0 && peepreport!=0) {
						printf("\nPHOLE: redundant TEST(1) deleted at %08X\n",(unsigned)curinstr);
					}
					if (curinstr->u2.prefixes[osprefix]!=0 && previnstr->u2.prefixes[osprefix]==0) {
						 previnstr->u2.prefixes[osprefix]=SHORTOPND;
						previnstr->csize++;
					}
					BDeleteInstr(curinstr,0)	/* Mark as deleted*/;
					BUpdateLiveRegs(frag);
					goto NextPass;
				}

				/*INC & DEC set the flags in a nonstandard way that is */
				/* Good enough for the signed comparisions only           */
				thirdinstr=BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
				if ((thirdinstr!=NULL) &&
					(prevop==INC||prevop==DEC)) {
					j=thirdinstr->opcode;
					if (j==JG||j==JGE||j==JL||j==JLE||j==JE||j==JNE||j==SETG ||
						j==SETGE||j==SETL||j==SETLEQ||j==SETE||j==SETNEQ) {
						if (optimtrace!=0 && peepreport!=0) {
							printf("\nPHOLE: redundant TEST(2) deleted at %08X\n",(unsigned)curinstr);
						}

						if (curinstr->u2.prefixes[osprefix]!=0 && previnstr->u2.prefixes[osprefix]==0) {
							previnstr->u2.prefixes[osprefix]=SHORTOPND;
							previnstr->csize++;
						}
						BDeleteInstr(curinstr,0)	/* Mark as deleted*/;
						BUpdateLiveRegs(frag);
						goto NextPass;
					}
				}
			}
			/* Is the flag register actually Used ?		*/
			BLiveSetAfterInstr(frag,curinstr,&rlive,&flive,&clive,&alive);
			if ((clive&(1<<FLAGREG))==0) {
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: redundant TEST(3) deleted at %08X\n",(unsigned)curinstr);
				}
				BDeleteInstr(curinstr,0)        /* Mark as deleted*/;	
				BUpdateLiveRegs(frag);
				goto NextPass;
			}
			/* Was the test on a recently sign extended register. if the
			   reg is dead change to avoid the extension                */

			if (previnstr!=NULL && prevop==MOVSX && previnstr->rd==previnstr->rs1
				&& previnstr->variant==OPRR && previnstr->rd==curinstr->rd) {
				BLiveSetAfterInstr(frag,curinstr,&rlive,&flive,&clive,&alive);
				if ((rlive&(257<<curinstr->rd))==0) {
					curinstr->u2.prefixes[osprefix]=SHORTOPND;
					curinstr->csize++;
					if (optimtrace!=0 && peepreport!=0) {
						 printf("\nPHOLE: Extend & TEST elided at  %08X\n",(unsigned)curinstr);
					}
					BDeleteInstr(previnstr,1);
				}
			}
		}

		previ=(int)BMachineInstr(curinstr->previnstr,PREVCHAIN);
		previnstr=(struct instrfmt*)(previ);
		if (previ!=0) {
			prevop=previnstr->opcode;
		}

		/* Look for an LEA which can be reduced to and INC or DEC    */
		/* This saves space rather than time since thew are both 1 bt*/
		/* instructions. However an AGI stall may be avoided         */
		if (op==LEA && abs(curinstr->disp)==1 && curinstr->rd==curinstr->rs1 &&
			(curinstr->privprops&SIBREQD)==0) {
			BLiveSetAfterInstr(frag,curinstr,&rlive,&flive,&clive,&alive);
			if ((clive&(1<<FLAGREG))==0) {
				if (curinstr->disp>0)  curinstr->opcode=INC; 
				else curinstr->opcode=DEC;
				curinstr->group=INTOPS;
				curinstr->datasize=4;
				curinstr->csize=1;
				curinstr->variant=OPPLUSR;
				curinstr->rref=1<<curinstr->rd;
				curinstr->cdef=1<<FLAGREG;
				curinstr->rs1=0;
				if (optimtrace!=0 && peepreport!=0) {
					printf("\n");
					printf("\nPHOLE: LEA transformed  at %08X\n",curi);
				}
				changes++;	 
				op=LEA;
			}
		}

		/* Various optimisations can follow an AND with literal        */
		/* Bit tests can be improved by eliding the previous shift     */
		/* and sign extension-truncations can sometimes be merged      */

		if (op==AND && (curinstr->variant==OPRLIT || curinstr->variant==OPRSLIT)) {
			thirdinstr=NULL;
			nextinstr=BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
			if (nextinstr!=NULL ) thirdinstr=BMachineInstr(nextinstr->nextinstr,NEXTCHAIN);
			if (nextinstr!=NULL && (nextinstr->props&CONDITIONALBRANCH)!=0 && 
				((frag->rout&curinstr->rdef)==0) && (previ!=0) && 
				(previnstr->rd==curinstr->rd) &&
				(prevop==SHR||prevop==SAR) &&
				(previnstr->variant==OPRSLIT)) {
				curinstr->u1.immval=curinstr->u1.immval<<previnstr->u1.immval;
				if (curinstr->variant==OPRSLIT &&
					(curinstr->u1.immval<-128||curinstr->u1.immval>127)) {
					curinstr->variant=OPRLIT;
					curinstr->csize+=3;
					curinstr->datasize=4;
				}
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: Rshift elided at %08X\n",curi);
					p5printinstr(curinstr);
				}
				changes++;
				BDeleteInstr(previnstr,0);
				goto NextPass;
			}
#if (MINCODESIZE==0)
			if (thirdinstr!=NULL && nextinstr->opcode==CMP && 
				(nextinstr->variant==OPRLIT || nextinstr->variant==OPRSLIT) &&
				(thirdinstr->props&CONDITIONALBRANCH)!=0 &&
				(thirdinstr->opcode==JE || thirdinstr->opcode==JNE) &&
				((frag->rout&curinstr->rdef)==0) && (previ!=0) && 
				previnstr->rd==curinstr->rd && nextinstr->rd==curinstr->rd &&
				(prevop==SHR||prevop==SAR) &&
				(previnstr->variant==OPRSLIT)) {
				curinstr->u1.immval=curinstr->u1.immval<<previnstr->u1.immval;
				if (curinstr->variant==OPRSLIT &&
					(curinstr->u1.immval<-128||curinstr->u1.immval>127)) {
					curinstr->variant=OPRLIT;
					curinstr->csize+=3;
					curinstr->datasize=4;
				}
				nextinstr->u1.immval=nextinstr->u1.immval<<previnstr->u1.immval;
				if (nextinstr->variant==OPRSLIT &&
					(nextinstr->u1.immval<-128||nextinstr->u1.immval>127)) {
					nextinstr->variant=OPRLIT;
					nextinstr->csize+=3;
					nextinstr->datasize=4;
				}
				if (optimtrace!=0 && peepreport!=0)
					printf("\nPHOLE: Rshift elided at %08X\n",curi);
				changes++;
				BDeleteInstr(previnstr,0);
				goto NextPass;
			}
#endif


			while (nextinstr!=NULL &&
				((curinstr->rdef&(nextinstr->rdef|nextinstr->rref))==0)) {
				nextinstr=BMachineInstr(nextinstr->nextinstr,NEXTCHAIN);
			}
			if (nextinstr!=NULL) {
				if (nextinstr->rd==curinstr->rd && nextinstr->opcode==AND &&
					(nextinstr->variant==OPRLIT || nextinstr->variant==OPRSLIT)) {
					nextinstr->u1.immval&=curinstr->u1.immval;
					if (nextinstr->variant==OPRLIT && nextinstr->u1.immval>-128 &&
						(nextinstr->u1.immval<=127)) {
						nextinstr->variant=OPRSLIT;
						nextinstr->csize+=(-3);
						nextinstr->datasize=1;
					}
					if (optimtrace!=0 && peepreport!=0) {
						printf("\nPHOLE: ANDs combined at %08X\n",curi);
					}
					changes++;
					BDeleteInstr(curinstr,0);
					goto NextPass;
				}
				if (nextinstr->rd==curinstr->rd && nextinstr->opcode==MOVSX &&
					nextinstr->rd==nextinstr->rs1 &&
					(curinstr->u1.immval&0x8000)==0) {
					if (optimtrace!=0 && peepreport!=0) {
						printf("\nPHOLE: redundant Sign-Ext(4) deleted at %08X\n",(unsigned) nextinstr);
					}
					changes++;
					BDeleteInstr(nextinstr,0);
					goto NextPass;
				}

				if (nextinstr->rd==curinstr->rd && nextinstr->opcode==SHL && previ!=0 ){
					thirdinstr=previnstr;
					do {
						if (thirdinstr==NULL) break;
						if (((thirdinstr->rref|thirdinstr->rdef)&curinstr->rref)!=0) break;
						thirdinstr=BMachineInstr(thirdinstr->previnstr,PREVCHAIN);
					} while (1);
					if (thirdinstr!=NULL && thirdinstr->rd==curinstr->rd &&
						(thirdinstr->opcode==SHR || thirdinstr->opcode==SAR) &&
						(thirdinstr->variant==OPRSLIT && OPRSLIT==nextinstr->variant)) {
						if (thirdinstr->u1.immval>nextinstr->u1.immval) {
							thirdinstr->u1.immval-=nextinstr->u1.immval;
							curinstr->u1.immval=curinstr->u1.immval<<nextinstr->u1.immval;
							BDeleteInstr(nextinstr,0);
						} else if (nextinstr->u1.immval>thirdinstr->u1.immval) {
							nextinstr->u1.immval-=thirdinstr->u1.immval;
							curinstr->u1.immval=curinstr->u1.immval<<thirdinstr->u1.immval;
							BDeleteInstr(thirdinstr,0);
						} else {
							curinstr->u1.immval=curinstr->u1.immval<<thirdinstr->u1.immval;
							BDeleteInstr(nextinstr,0);
							BDeleteInstr(thirdinstr,0);
						}

						if (curinstr->variant==OPRSLIT &&
							(curinstr->u1.immval<-128 || curinstr->u1.immval>127)) {
							curinstr->variant=OPRLIT;
							curinstr->csize+=3;
						}
						if (optimtrace!=0 && peepreport!=0) {
							printf("\nPHOLE: SH-AND-SH improved at %08X\n",curi);
						}
						changes++;
						goto NextPass;
					}
				}
			}

			/* This next peephole must follow the others since we need to    */
			/* remove redundant shifts and sign extends before complicating  */
			/* everything by changing somes ands to tests                    */

			nextinstr=BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
			if (nextinstr!=NULL && (nextinstr->props&CONDITIONALBRANCH)!=0 &&
				(frag->rout&curinstr->rdef)==0) {
				curinstr->opcode=TEST;
				if (curinstr->variant==OPRSLIT) 	/* no such variant for TEST */{
					if (targetvariant!=0 || curinstr->rd>3) {
						curinstr->csize+=3;
						curinstr->datasize=4;
						curinstr->variant=OPRLIT;
					} else {
						curinstr->variant=OPBRMLIT;
						curinstr->privprops|=BYTEREGOP;
					}
				}

				/* Because of sign bit propagation an ANDL x'80' will     */
				/* remain a TESTL so extra code is needed here to reduce  */
				/* this case to a TESTB                                   */

				if (curinstr->variant==OPRLIT && ((unsigned)curinstr->u1.immval>>8)==0 &&
					curinstr->rd<=3) {
					curinstr->variant=OPBRMLIT;
						curinstr->csize=3;
					curinstr->privprops|=BYTEREGOP;
				}
				curinstr->rdef=0;
				if (curinstr->variant==OPBRMLIT && previ!=0 &&
					curinstr->rs1==previnstr->rd &&
					(prevop==LB || prevop==LBU ||prevop==LBNOX)) {
					/* No change to csize as LB & LBU are 2 byte opcodes */
					if (prevop==LBNOX) previnstr->csize++;
					previnstr->opcode=TEST;
					previnstr->variant=OPBMEMLIT;
					previnstr->u1.immval=curinstr->u1.immval;
					previnstr->rdef=0;
					previnstr->cdef|=(1<<FLAGREG);
					BDeleteInstr(curinstr,0);
				}
				if (curinstr->variant==OPRLIT && previ!=0 &&
					(prevop==LH || prevop==LHU) &&
					curinstr->rs1==previnstr->rd &&
					(curinstr->u1.immval&0xffff00ff)==0) {
					previnstr->opcode=TEST;
					previnstr->variant=OPBMEMLIT;
					previnstr->datasize=1;
					/* previnstr->csize-=3;*/
					increasedataoffsetby(previnstr,1);
					previnstr->u1.immval=curinstr->u1.immval>>8;
					previnstr->rdef=0;
					previnstr->cdef|=(1<<FLAGREG);
					previnstr->u2.prefixes[osprefix]=0;
					BDeleteInstr(curinstr,0);
				}
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: AND->TEST change at %08X\n",curi);
				}
				changes++;
				goto NextPass;
			}

			/* Finally look for the following not very commom sequence    */
			/*      and reg,2**N                                          */
			/*      cmp reg,2**n                                          */
			/*      jcc   Label                                           */
			/* the cmp can be deleted and the jcc changed to use the flag */
			/* settings of the and. This should be changed into a TEST    */
			/* during the next pass                                       */
			/* the JLT case is a branch never but deleting a branch at    */
			/* this time makes the topology of the program inconsistent   */
			/* with enormous complications. If this (Silly) case is found */
			/* we skip this optimisation                                  */
			if (nextinstr!=NULL && nextinstr->opcode==CMP &&
				(nextinstr->variant==OPRSLIT || nextinstr->variant==OPRLIT) &&
				nextinstr->rd==curinstr->rd && nextinstr->u1.immval==curinstr->u1.immval && 
				curinstr->u1.immval!=0x80000000
				&& (curinstr->u1.immval&(curinstr->u1.immval-1))==0) {
				thirdinstr=BMachineInstr(nextinstr->nextinstr,NEXTCHAIN);
				if (thirdinstr!=NULL && (thirdinstr->props&CONDITIONALBRANCH)!=0 
					&& thirdinstr->opcode!=JL)             {
					if (thirdinstr->opcode==JE || thirdinstr->opcode==JLE ||
					thirdinstr->opcode==JGE)  thirdinstr->opcode=JNZ;
					else thirdinstr->opcode=JZ;
					BDeleteInstr(nextinstr,0);
					if (optimtrace!=0 && peepreport!=0) {
						printf("\nPHOLE: CMP 2**N change at %8x\n ",curi);
					}
					changes++;
					goto NextPass;
				}
			}
		}

		/* Look for a SIB byte that can be enhanced to avoid a       */
		/* shift occurrs when picking up every second array element  */

		if ((curinstr->privprops&SIBREQD)!=0 && previ!=0 && prevop==SHL &&
			previnstr->variant==OPRSLIT && 
			(((unsigned)curinstr->sib>>6)+previnstr->u1.immval)<=3 && 
			curinstr->rs2==previnstr->rd) {
			BLiveSetAfterInstr(frag,curinstr,&rlive,&flive,&clive,&alive);
			if ((rlive&(257<<curinstr->rs2))==0) {
				curinstr->sib+=(previnstr->u1.immval<<6);
				BDeleteInstr(previnstr,0);
				/* Live regs are not changed by this optimisation    */
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: SIB use enhanced at %08X\n",curi);
				}
				changes++;
				goto NextPass;
			}
		}

		/* Look for a byte load followed by a shift or and such that */
		/* the register does not need to be sign or zero extended    */

		if (targetvariant==0 && final>0 && previ!=0 &&
			(prevop==LB || prevop==LBU) &&
			(curinstr->variant==OPRLIT || curinstr->variant==OPRSLIT || curinstr->variant==OPBRMLIT)) {
			if (((op==SHL && 24<=curinstr->u1.immval && curinstr->u1.immval<=31) ||
			  ((op==AND || op==TEST) && 0<curinstr->u1.immval && curinstr->u1.immval<=255)) &&
				curinstr->rd==previnstr->rd && curinstr->rd<=3) {
				prevop=LBNOX; previnstr->opcode=LBNOX;
				previnstr->privprops|=BYTEREGOP;
				previnstr->csize-=1;
				/* Live regs are not changed by this optimisation    */

	 			if (optimtrace!=0 && peepreport!=0)
					printf("\nPHOLE: redundant Sign-Ext(1) deleted at %08X\n",previ);
				changes++;
				goto NextPass;
			} else {
				thirdinstr=BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
				if (thirdinstr!=NULL && thirdinstr->opcode==AND &&
					thirdinstr->variant==OPRSLIT && thirdinstr->rd==curinstr->rd &&
					curinstr->rd==previnstr->rd && curinstr->rd<=3 &&
					(op==SHR || op==SAR) &&
					1<=curinstr->u1.immval && curinstr->u1.immval<=7 &&
					(thirdinstr->u1.immval<<curinstr->u1.immval)<=255) {
					prevop=LBNOX; previnstr->opcode=LBNOX;
					previnstr->privprops|=BYTEREGOP;
					previnstr->csize+=-1;
					if (optimtrace!=0 && peepreport!=0)
						printf("\nPHOLE: redundant Sign-Ext(1A) deleted at %08X\n",previ);
					changes++;
					/* Live regs are not changed by this optimisation    */
					goto NextPass;
				}
				if (thirdinstr!=NULL && thirdinstr->opcode==SB &&
					thirdinstr->rd==curinstr->rd &&
					curinstr->rd==previnstr->rd && curinstr->rd<=3 &&
					(op==AND || op==OR || op==XOR || op==SHL || op==ADD || op==SUB )) {
					BLiveSetAfterInstr(frag,thirdinstr,&rlive,&flive,&clive,&alive);
					if ((clive&(1<<FLAGREG))==0 && (rlive&(1<< curinstr->rd))==0) {
						prevop=LBNOX; previnstr->opcode=LBNOX;
						previnstr->privprops|=BYTEREGOP;
						previnstr->csize+=-1;
						if (optimtrace!=0 && peepreport!=0)
							printf("\nPHOLE: redundant Sign-Ext(1B) deleted at %08XC\n",previ);
						changes++;
						goto NextPass;
					}
				}
			}
		}

		/* Repeat the simpler forms of the above with the LB not adjacent */

		if (targetvariant==0 && final>0 && previ!=0 &&
			(curinstr->variant==OPRLIT || curinstr->variant==OPRSLIT || curinstr->variant==OPBRMLIT) &&
			(op==AND || op==TEST) && 0<curinstr->u1.immval && curinstr->u1.immval<=255 &&
			curinstr->rd<=3) {
			thirdinstr=previnstr;
			do {
				if (thirdinstr==NULL) break;
				if (((thirdinstr->rref|thirdinstr->rdef)&curinstr->rref)!=0) break;
				thirdinstr=BMachineInstr(thirdinstr->previnstr,PREVCHAIN);
			} while (1);
			if (thirdinstr!=NULL && (thirdinstr->opcode==LB || thirdinstr->opcode==LBU) &&
				thirdinstr->rd==curinstr->rd) {
				thirdinstr->opcode=LBNOX;
				thirdinstr->privprops|=BYTEREGOP;
				previnstr->csize--;
				if (optimtrace!=0 && peepreport!=0)
					printf("\nPHOLE: redundant Sign-Ext(1C) deleted at %08X\n",(unsigned)thirdinstr);
				changes++;
				goto NextPass;
			}
		}
		/* Repeat above optimisation for 16 bit operands    */

		if (targetvariant==0 && final>0 && previ!=0 &&
			(prevop==LH || prevop==LHU) &&
			(curinstr->variant==OPRLIT || curinstr->variant==OPRSLIT)) {

			if (((op==SHL && 16<=curinstr->u1.immval && curinstr->u1.immval<=31) ||
				((op==AND ||op==TEST) &&
				(0<curinstr->u1.immval && curinstr->u1.immval<=0xFFFF))) &&
				curinstr->rd==previnstr->rd) {
				/* this operation does not save space but does save time and may well
				   rule out the and Sx..,%ah instructions which saves a lot
				   of space. Duck out in the case                                   */
#if (MINCODESIZE!=0)
				if (prevop=LHU && op==AND && curinstr->rd<=3 &&
					(curinstr->u1.immval&255)==255) goto NextPass;
#endif
				previnstr->opcode=MOV;
				previnstr->u2.prefixes [osprefix]=SHORTOPND;
				/* Live regs are not changed by this optimisation    */
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: redundant Sign-Ext(2) deleted at %08X\n",previ);
				}
				changes++;
			} else if (op==SHR && curinstr->u1.immval==8) {
				previnstr->opcode=LBU;
				/* previnstr->csize--; */ 
				previnstr->datasize=1;
				previnstr->u2.prefixes[osprefix]=0;
				increasedataoffsetby(previnstr,1);
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: redundant SHR elided at %08X\n",(unsigned)curinstr);
					p5printinstr(previnstr);
				}
				BDeleteInstr(curinstr,0);
				changes++;
			} else {
				thirdinstr=BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
				if (thirdinstr!=NULL && thirdinstr->opcode==AND && 
					(thirdinstr->variant==OPRLIT || thirdinstr->variant==OPRSLIT) &&
					(thirdinstr->rd==curinstr->rd && curinstr->rd==previnstr->rd) &&
					(op==SHR || op==SAR) &&
					1<=curinstr->u1.immval && curinstr->u1.immval<=15 &&
					(thirdinstr->u1.immval<<curinstr->u1.immval)<=0xFFFF) {
					previnstr->opcode=MOV;
					previnstr->u2.prefixes [osprefix]=SHORTOPND;
					/* Live regs are not changed by this optimisation    */
					if (optimtrace!=0 && peepreport!=0) {
						printf("\nPHOLE: redundant Sign-Ext(2A) deleted at %08X\n",previ);
					}
				}
			}
		}

		/* Look for a byte load followed by a byte store where*/
		/* the loaded register is dead after th store.        */
		/* Remove any unnecessary sign extension              */

		if (final>0 && previ!=0 && 
			(prevop==LB || prevop==LBU) &&
			op==SB && curinstr->rd==previnstr->rd && previnstr->rd<=3 &&
			((curinstr->privprops&FIXEDINSTR)==0 || curinstr->rs1!=curinstr->rd) &&
			((curinstr->privprops&SIBREQD)==0 || curinstr->rs2!=curinstr->rd)) {
			BLiveSetAfterInstr(frag,curinstr,&rlive,&flive,&clive,&alive);
			if ((rlive&(257<<curinstr->rd))==0) {
				previnstr->opcode=LBNOX;
				previnstr->privprops=previnstr->privprops|BYTEREGOP;
				previnstr->csize=previnstr->csize-1;
				/* Live regs are not changed by this optimisation    */
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: redundant Sign-Ext(3) deleted at ");
					phex(previ);
					printf("\n");
					p5printinstr(previnstr);
				}
				changes++; goto NextPass;
			}
		}

		/* Repeat above optimisation for 16 bit operands    */

		if (final>0 && previ!=0 &&
			(prevop==LH || prevop==LHU) &&
			(op==SH) &&
			((curinstr->privprops&FIXEDINSTR)==0 || curinstr->rs1!=curinstr->rd) &&
			((curinstr->privprops&SIBREQD)==0 || curinstr->rs2!=curinstr->rd)) {
			BLiveSetAfterInstr(frag,curinstr,&rlive,&flive,&clive,&alive);
			if ((rlive&(257<<curinstr->rd))==0) {
				previnstr->opcode=MOV;
				previnstr->u2.prefixes [osprefix]=SHORTOPND;
				/* Live regs are not changed by this optimisation    */
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: Zero-Ext improved at %08X\n",(unsigned)curinstr);
				}
			}
		}

		/* Finally look for LBUs which can become XOR &MOVB      */
		/* which is quicker and more likely to pair but not on P6*/

		if (targetvariant==0 && MINCODESIZE==0 && final>0 && previ!=0 && 
			prevop==LBU && previnstr->rd<=3 && (previnstr->rdef&previnstr->rref)==0) {
			thirdinstr=BInsertInstr(frag,previnstr);
			thirdinstr->rs1=previnstr->rd;	 
			thirdinstr->rd=previnstr->rd;
			thirdinstr->opcode=XOR;	 
			thirdinstr->group=instrgroup [XOR];
			thirdinstr->props=DESTROYABLE;	 
			thirdinstr->csize=2;
			thirdinstr->rmbyte=0xC0;	 
			thirdinstr->variant=OPRR;
			thirdinstr->rdef=257<<previnstr->rd;
			thirdinstr->cdef=1<<FLAGREG;
			previnstr->opcode=LBNOX;
			previnstr->privprops|=BYTEREGOP;
			previnstr->csize--;
			previnstr->rref|=(previnstr->rdef&255);
			if (optimtrace!=0 && peepreport!=0) {
				printf("\nPHOLE: redundant Sign-Ext(5) deleted at %08X\n",previ);
				p5printinstr(previnstr);
			}
		}

		/* Look for pointless ops involving zero such ops can */
		/* arise out of MAX&MIN eops and are  best dealt with */
		/* in the peepholer                                   */

		if (previ!=0 && prevop==FLDZ && (op==FADDP || op==FSUBP)) {
			if (optimtrace!=0 && peepreport!=0) {
				printf("\nPHOLE: redundant FLDZ deleted at %08X\n",(unsigned)curinstr);
			}
			BDeleteInstr(curinstr,0)	/* Mark as deleted*/;
			BDeleteInstr(previnstr,0)	/* Mark as deleted*/;
			BUpdateLiveRegs(frag);
			changes++;
			goto NextPass;
		}

		/* Look for repeated initialisations and save a store access*/

		if (curinstr->opcode==FLDZ || curinstr->opcode==FLD1) {
			nextinstr=BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
			j=0;
			while (nextinstr!=NULL) {
				if ((nextinstr->props&(BRANCH|ANYCALL|JUMPINSTR|WRAPPERINSTR|UNKNOWNFLOW))!=0)   break;
				if (((nextinstr->cdef&(1<<FSTP))|nextinstr->fdef)!=0 && j<=20) {
					fpads [j]=nextinstr;	 
					j++;
				}
				nextinstr=BMachineInstr(nextinstr->nextinstr,NEXTCHAIN);
			}
			if (j>=2) {
				nextinstr=fpads [0];	 
				thirdinstr=fpads [1];
				if (thirdinstr->opcode==curinstr->opcode && 
					thirdinstr->fdef==curinstr->fdef && nextinstr->group==FPSTORE &&
					instrform [nextinstr->opcode]==F2pFORM) {
					nextinstr->opcode+=3;
					nextinstr->cdef&=(~(1<<FSTP));
					BDeleteInstr(fpads [1],0);
					changes++;
					if (optimtrace!=0 && peepreport!=0) {
						printf("\nPHOLE: redundant FP stack reload deleted at %08X\n",previ);
					}
				}
			}
		}

		/* Look for FP truncations preceding 4 byte store&pop */

		if (previ!=0 && (previnstr->privprops&PRECISIONREDN)!=0 &&
			(curinstr->privprops&PRECISIONREDN)!=0) {
			nextinstr=BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
			while (nextinstr!=NULL) {
				if ((nextinstr->fdef|nextinstr->fref)!=0 || 
					((nextinstr->props&(BRANCH|ANYCALL|JUMPINSTR|WRAPPERINSTR|UNKNOWNFLOW))!=0))   break ;
				nextinstr=BMachineInstr(nextinstr->nextinstr,NEXTCHAIN);
			}
			if (nextinstr!=0 && nextinstr->opcode==FSTPm) {
				BDeleteInstr(curinstr,0)	/* Mark as deleted*/;
				BDeleteInstr(previnstr,0)	/* Mark as deleted*/;
				changes++;
				goto NextPass;
			}
		}

		/* Look for an integer load followed by a store back into */
		/* the same location. This is commonly a result of a C smt*/
		/* x=MACRO(x) where MACRO has a null expansion            */

		if (curinstr->group==INTSTORE && previ!=0 && previnstr->group==INTLOAD &&
			curinstr->datasize==previnstr->datasize && curinstr->rd==previnstr->rd &&
			(previnstr->rdef&previnstr->rref)==0) {
			if (p5memoryoverlap(curinstr,previnstr,1)==MOEXACT) {
				BDeleteInstr(curinstr,0);	/* Mark as deleted */
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: redundant Store deleted at %08X\n",(unsigned)curinstr);
				}
				goto NextPass;
			}
		}

		/* Look for pairs of BSWAPs that operate on the same      */
		/* integer register and delete both                        */

		if (op==BSWAP && previ!=0) {
			thirdinstr=previnstr;
			while (thirdinstr!=NULL && (thirdinstr->props&ANYCALL)==0 &&
				(((thirdinstr->rdef|thirdinstr->rref)&curinstr->rdef))==0) {
				thirdinstr=BMachineInstr(thirdinstr->previnstr,PREVCHAIN);
			}
			if (thirdinstr!=NULL && thirdinstr->opcode==BSWAP && 
				curinstr->rd==thirdinstr->rd) {
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: redundant BSWAP deleted at %08X\n",(unsigned)curinstr);
				}
				BDeleteInstr(curinstr,0)	/* Mark as deleted*/;
				BDeleteInstr(thirdinstr,0)	/* Mark as deleted*/;
				changes++;
				goto NextPass;
			}
		}

		/* Look for unnecessary FXCHs which may be put in by the   */
		/* next optimisation. They often take 0 beats on Pentium   */
		/* but they cost on 486 and are inelegant                  */

		if (previ!=0 && prevop==FXCH) {
			if (op==FXCH && previnstr->fdef==curinstr->fdef) {
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: redundant FXCH deleted at %08X\n",(unsigned)curinstr);
				}
				BDeleteInstr(curinstr,0)	/* Mark as deleted*/;
				BDeleteInstr(previnstr,0)	/* Mark as deleted*/;
				changes++;
				goto NextPass;
			}
			if ((op==FADDP || op==FSUBP || op==FMULP) &&
				previnstr->fdef==curinstr->fref) {
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: redundant FXCH deleted at %08X\n",(unsigned)previnstr);
				}
				BDeleteInstr(previnstr,0)			/* Mark as deleted*/;
				if (op==FSUBP)  curinstr->opcode=FSUBRP;	/* Reverse the subtract */
				changes++;
				goto NextPass;
			}
		}


		/* Look for simple 4 byte assign done via int regs which  */
		/* would be more efficient done via FP stack              */

		if (previ!=0 && previnstr->group==INTSTORE && curinstr->group==FPLOAD &&
			curinstr->datasize==4 && curinstr->opcode!=FILD &&
			p5memoryoverlap(previnstr,curinstr,1)==MOEXACT) {
			BLiveSetAfterInstr(frag,previnstr,&rlive,&flive,&clive,&alive);
			if ((rlive&(1<<previnstr->rd))==0) {
				thirdinstr=BMachineInstr(previnstr->previnstr,PREVCHAIN);
				while (thirdinstr!=NULL &&
					(thirdinstr->rref|(thirdinstr->rdef&(257<<previnstr->rd)))==0 &&
					(thirdinstr->fref|thirdinstr->fdef)==0) {
					thirdinstr=BMachineInstr(thirdinstr->previnstr,PREVCHAIN);
				}
				if (thirdinstr!=NULL && thirdinstr->group==INTLOAD &&
				   p5memoryoverlap(thirdinstr,curinstr,0)==MOEXACT) {
					thirdinstr->opcode=FLDm;
					thirdinstr->rd=curinstr->rd;
					thirdinstr->rdef=0;
					thirdinstr->fdef=curinstr->fdef;
					thirdinstr->cdef=1<<FSTP;
					thirdinstr->cref=(1<<FSTP)|(1<<FPSCR);
					thirdinstr->variant=FOPRM;
					thirdinstr->group=FPLOAD;
					previnstr->opcode=FSTm;
					previnstr->rref&=(~(1<<curinstr->rd));
					previnstr->rd=curinstr->rd;
					previnstr->fref=curinstr->fdef;
					previnstr->cref=(1<<FPSCR)|(1<<FSTP);
					previnstr->variant=FOPRM;
					previnstr->group=FPSTORE;
					if (optimtrace!=0 && peepreport!=0) {
						printf("\nPHOLE: Store changed to use FSTK at %08X\n",(unsigned)curinstr);
					}
					BDeleteInstr(curinstr,0);
					changes++;
					goto NextPass;
				}
			}
		}

		/* Look for Floating store and pop following a FDUPL       */
		/* (is FLD %st(0) and delete the duplicate by changing the */
		/* store and pop to a store                                */

		if (previ!=0 && previnstr->variant==FOPPLUSR && prevop==FLDd && 
			previnstr->rd==previnstr->rs1 && group==FPSTORE &&
			instrform [op]==F2pFORM && op!=FSTPq && op!=FISTPd) {
			curinstr->opcode=op+3;			/* non pop form */
			curinstr->cdef&=(~(1<<FSTP));
			curinstr->rd++;
			curinstr->fref=curinstr->fref<<1;
			BDeleteInstr(previnstr,0);
			if (optimtrace!=0 && peepreport!=0) {
				printf("\nPHOLE: FP dup deleted at %08X\n",curi);
			}
			changes++;	 
			goto NextPass;
		}

		/* Look for Floating store and pop followed by fetch back */
		/* and change into store without pop and delete fetch     */
		/* Can only do this if both instructions marked DELETABLE */
		/* since store & fetch back is used in place of round to  */
		/* single precision which is not implemented !            */
		/* Also if there have been exact comparisons of 4 byte    */
		/* quanities in this routine skip this section since      */
		/* numeric differences can occur as a result of GREATER   */
		/* accuracy caused by this optimisation.                  */
		/* A further hazard is load-stores within  the FP-stack   */
		/* These must be eliminated by checking the prop bits     */
		/* This optimisation cant work with extended reals        */
		/* as there is no store extended without popping          */

		if (previ!=0 && curinstr->group==FPLOAD && 
			(curinstr->props&(LOADINSTR|DESTROYABLE))==(LOADINSTR|DESTROYABLE)) {
			rdef=0;
			while (previnstr->fdef==0 && (previnstr->cdef&(1<<FSTP))==0 && 
				previnstr->group!=FPSTORE && (previnstr->props&ANYCALL)==0 && 
				prevop!=FXCH &&
				((previnstr->props&STOREINSTR)==0 || p5memoryoverlap(curinstr,previnstr,0)==MONO)) {
				rdef|=previnstr->rdef;
				previ=(int)BMachineInstr(previnstr->previnstr,PREVCHAIN);
				if (previ==0)   break ;
				previnstr=(struct instrfmt*)(previ);
			}
			prevop=previnstr->opcode;
			/**/
			/* Check that the location referenced by previ is not accessed by an integer */
			/* instruction before we reach curinstr. Unlikely but alas possible          */
			/**/

			if ((previnstr->props&STOREINSTR)!=0) {
				j=0;
				thirdinstr=BMachineInstr(previnstr->nextinstr,NEXTCHAIN);
				while (thirdinstr!=curinstr) {
					if ((thirdinstr->props&(LOADINSTR|STOREINSTR))!=0 && 
						p5memoryoverlap(thirdinstr,previnstr,0)!=MONO)  j=1;
					thirdinstr=BMachineInstr(thirdinstr->nextinstr,NEXTCHAIN);
				}
			}
			if (previnstr->group==FPSTORE && instrform [prevop]==F2pFORM && prevop!=FISTPd && 
				(previnstr->props&STOREINSTR)!=0 && j==0 && (previnstr->rref&rdef)==0) {
				rdef&=curinstr->rref|previnstr->rref;	/* changed base regs */
				if (rdef==0)  j=1; else j=0;
				if ((curinstr->datasize==previnstr->datasize && previnstr->datasize==8) && 
					(previnstr->props&DESTROYABLE)!=0) {
					if (MOEXACT==p5memoryoverlap(curinstr,previnstr,j)) {
						if (optimtrace!=0 && peepreport!=0) {
							printf("\nPHOLE:: FP reload(8) deleted at %08X  %d\n",(unsigned)curinstr,rdef);
						}
						previnstr->opcode+=3;		/* To non pop version */
						previnstr->cdef&=(~(1<<FSTP));		/* does not pop FSTP  */
						BDeleteInstr(curinstr,0)	/* Mark as deleted*/;
						goto NextPass;	/* This does not alter liveness */
					}
				}

				/* 4 byte case is complicated since this might be a deliberate    */
				/* store and reload to truncate the value                         */

				nextinstr=BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
				thirdinstr=BMachineInstr(previnstr->previnstr,PREVCHAIN);
				while (thirdinstr!=NULL && (thirdinstr->fref|thirdinstr->fdef)==0 && 
					(thirdinstr->props&ANYCALL)==0) {
					thirdinstr=BMachineInstr(thirdinstr->previnstr,PREVCHAIN);
				}

				if (curinstr->datasize==previnstr->datasize && previnstr->datasize==4 && 
					(previnstr->props&DESTROYABLE)!=0 && 
					 ((thirdinstr!=NULL && thirdinstr->group==FPLOAD && thirdinstr->datasize==4) ||
					   (nextinstr!=NULL && nextinstr->group==FPSTORE && nextinstr->datasize==4))) {
					if (MOEXACT==p5memoryoverlap(curinstr,previnstr,j)) {
						if (optimtrace!=0 && peepreport!=0) {
							printf("\nPHOLE:: FP reload(4) deleted at %08X  %d\n",(unsigned)curinstr,rdef);
						}
						previnstr->opcode+=3;		/* To non pop version */
						previnstr->cdef&=(~(1<<FSTP));		/* does not pop FSTP  */
						BDeleteInstr(curinstr,0)	/* Mark as deleted*/;
						goto NextPass;	/* This does not alter liveness */
					}
				}

				/* On Pentium there are additional latency cycles when a FPSTORE  */
				/* follows an arithmetic operation or a load. Check for these and */
				/* rearrange using the fact that FXCH normally takes 0 beats.     */
				/* This changes makes for worse code on both 386 and 486 chips    */

#if (2==3)
				if (final>0 && p5memoryoverlap(curinstr,previnstr,j)==MONO && 
					curinstr->rd>=13	/*dont go too deep */) {
					if (nextinstr!=NULL && fp0popop(nextinstr->opcode)==1) {
						if ((nextinstr->props&LOADINSTR)==0 ||
							p5memoryoverlap(nextinstr,previnstr,j)==MONO) {
							thirdinstr=ARCH(appendfxch(frag,nextinstr->nextinstr,previnstr->rd-1));
							BMoveAfter(frag,frag,previnstr,thirdinstr);
							curinstr->rd--;
							curinstr->fdef=(unsigned)curinstr->fdef>>1;
							previnstr->rd--;
							previnstr->fdef=(unsigned)previnstr->fdef>>1;
							previnstr->fref=(unsigned)previnstr->fref>>1;
							nextinstr->rd--;
							if (nextinstr->rs1>FRBASE)  nextinstr->rs1--;
							nextinstr->fdef=(unsigned)nextinstr->fdef>>1;
							nextinstr->fref=(unsigned)nextinstr->fref>>1;
							changes++;
						}
					} else if (nextinstr!=NULL && fp1popop(nextinstr->opcode)==1 && 
						nextinstr->group==FPCOMPARE/* nothing pushed back*/) {
						if ((nextinstr->props&LOADINSTR)==0 || 
						    p5memoryoverlap(nextinstr,previnstr,j)==MONO) {
							BMoveAfter(frag,frag,previnstr,nextinstr);
							curinstr->rd--;
							curinstr->fdef=(unsigned)curinstr->fdef>>1;
							nextinstr->rd--;
							if (nextinstr->rs1>FRBASE)  nextinstr->rs1--;
							nextinstr->fdef=(unsigned)nextinstr->fdef>>1;
							nextinstr->fref=(unsigned)nextinstr->fref>>1;
							changes++;
						}
					} else {  /* Just swop the load and store */

						thirdinstr=ARCH(appendfxch(frag,curinstr->nextinstr,previnstr->rd-1));
						BMoveAfter(frag,frag,previnstr,thirdinstr);
						curinstr->rd--;
						curinstr->fdef=(unsigned)curinstr->fdef>>1;
						previnstr->rd--;
						previnstr->fdef=(unsigned)previnstr->fdef>>1;
						previnstr->fref=(unsigned)previnstr->fref>>1;
						changes++;
					}

				}
#endif
			}	/* if previnstr_group=FPSTORE */

		}	/* if curinstr_group=FPload */
		previ=(int)BMachineInstr(curinstr->previnstr,PREVCHAIN);
		previnstr=(struct instrfmt*)(previ);
		if (previ!=0) {
			prevop=previnstr->opcode;
		}



		/* Look for mov immediates of 1 or 0 and replace   */
		/* provided the FLAGS are not live at this point   */
		if (op==MOV && curinstr->variant==OPPLUSRLIT && 
			(curinstr->privprops&(FIXEDINSTR|FIXEDLIT))==0 && (0<=curinstr->u1.immval && 
			curinstr->u1.immval<=1)) {
			j=curinstr->u1.immval;
			BLiveSetAfterInstr(frag,curinstr,&rlive,&flive,&clive,&alive);
			if ((clive&(1<<FLAGREG))==0) 	/* MOV does not change flags */{
				curinstr->opcode=XOR;	/* But XOR does */
				curinstr->u1.immval=0;
				curinstr->csize=2;
				curinstr->group=instrgroup [XOR];
				curinstr->rs1=curinstr->rd;
				curinstr->rmbyte=0xC0;
				curinstr->variant=OPRR;
				curinstr->cdef=1<<FLAGREG;
				if (j==1) 	/* Now INC the zero */{
					thirdinstr=BInsertInstr(frag,curinstr->nextinstr);
					thirdinstr->opcode=INC;
					thirdinstr->rd=curinstr->rd;
					thirdinstr->group=instrgroup [INC];
					thirdinstr->props=DESTROYABLE;
					thirdinstr->rref=1<<curinstr->rd;
					thirdinstr->rdef=257<<curinstr->rd;
					thirdinstr->cdef=1<<FLAGREG;
					thirdinstr->variant=OPPLUSR;
					thirdinstr->csize=1;
				}
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: MOV-Literal improved at %08X\n",(unsigned)curinstr);
				}
				goto NextPass;
			}
		}

		/* look for the complex sequence     mov safereg,wkreg      */
		/*                                   op  wkreg              */
		/*                                   mov wkreg,safereg      */
		/* and if wkreg dead then reduce to a single instr          */

		nextinstr=BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
		if (previ!=0 && (previnstr->props&COPYINSTR)!=0 && previnstr->rd==curinstr->rd && 
			(curinstr->rdef&0xFFFF)==(257<<curinstr->rd) && (group==INTOPS || group==INTOPSu)) {
			if (nextinstr!=NULL && (nextinstr->props&COPYINSTR)!=0 && 
				nextinstr->rs1==curinstr->rd && nextinstr->rd==previnstr->rs1) {
				BLiveSetAfterInstr(frag,nextinstr,&rlive,&flive,&clive,&alive);
				/*   printstring("double copy stage 2"); newline */
				/*   p5 PrintInstr(previ); p5 PrintInstr(curi); p5 PrintInstr(nexti); newline*/
				if ((rlive&(257<<curinstr->rd))==0 && 
					((curinstr->privprops&SIBREQD)==0 || curinstr->rd!=curinstr->rs2)) {
					if (curinstr->rs1==curinstr->rd)  curinstr->rs1=nextinstr->rd;
					curinstr->rd=nextinstr->rd;
					curinstr->rdef=257<<curinstr->rd;
					curinstr->rref=(curinstr->rref&(~(1<<previnstr->rd)))|(1<<curinstr->rd);
					if (curinstr->variant==OPEAXLIT) {
						curinstr->variant=OPRLIT; 
						curinstr->csize++;
					}
					if (curinstr->variant==OPALLIT) {
						curinstr->variant=OPBRMLIT; 
						curinstr->csize++;
					}
					BDeleteInstr(previnstr,0);
					BDeleteInstr(nextinstr,0);
					if (optimtrace!=0 && peepreport!=0) {
						printf("\nPHOLE: double copy removed at %08X",curi);
					}
					goto NextPass;
				}
			}
		}

#if (MINCODESIZE!=0)
		/* look for the complex sequence     lbnox var,%xl       */
		/*                                   orb   $0x..,%xl     */
		/*                                   sb    %xl,var       */
		/* and if xh dead reduce to single lit-store instr       */
		/* this saves a lot of space but is slow due to bus lock */

		if (previ!=0 && prevop==LBNOX && (previnstr->rref&previnstr->rdef)==0 &&
			(op==OR || op==AND || op==XOR) &&
			(curinstr->variant==OPBRMLIT || curinstr->variant==OPRSLIT || curinstr->variant==OPRLIT) &&
			curinstr->rd==previnstr->rd && nextinstr!=NULL &&
			nextinstr->opcode==SB && nextinstr->rd==curinstr->rd &&
			p5memoryoverlap(previnstr,nextinstr,1)==MOEXACT) {
			BLiveSetAfterInstr(frag,nextinstr,&rlive,&flive,&clive,&alive);
			if ((rlive&(257<<curinstr->rd))==0) {
				previnstr->variant=OPBMEMLIT;
				previnstr->props|=STOREINSTR;
				previnstr->group=RWMEM;
				previnstr->opcode=op;
				previnstr->rdef=0;
				previnstr->csize++;
				previnstr->u1.immval=curinstr->u1.immval;
				BDeleteInstr(curinstr,0);
				BDeleteInstr(nextinstr,0);
				if (optimtrace!=0 && peepreport!=0) 
					printf("\nPHOLE:Op on  Store byte issued at %08X",previnstr);
				changes++;
				goto NextPass;
			}
		}

		/* look for the Vcomplex sequence    lbnox var,%xl       */
		/*                                   andb  $0x..,xl      */
		/*                                   orb   $0x..,%xl     */
		/*                                   sb    %xl,var       */
		/* and if xh dead reduce to two lit-store instrs         */
		/* this saves a lot of space but is slow due to bus lock */

		thirdinstr=NULL;
		if (previ!=0 && prevop==LBNOX && op==AND && nextinstr!=NULL) {
			thirdinstr=BMachineInstr(nextinstr->nextinstr,NEXTCHAIN);
		}
		if (thirdinstr!=NULL && (previnstr->rref&previnstr->rdef)==0 &&
			(nextinstr->opcode==OR ||  nextinstr->opcode==XOR) &&
			(curinstr->variant==OPBRMLIT || curinstr->variant==OPRSLIT || curinstr->variant==OPRLIT) &&
			(nextinstr->variant==OPBRMLIT || nextinstr->variant==OPRSLIT || nextinstr->variant==OPRLIT) &&
			curinstr->rd==previnstr->rd && nextinstr->rd==curinstr->rd &&
			thirdinstr->opcode==SB && thirdinstr->rd==curinstr->rd &&
			p5memoryoverlap(previnstr,thirdinstr,1)==MOEXACT) {
			BLiveSetAfterInstr(frag,thirdinstr,&rlive,&flive,&clive,&alive);
			if ((rlive&(257<<curinstr->rd))==0) {
				previnstr->variant=OPBMEMLIT;
				previnstr->props|=STOREINSTR;
				previnstr->group=RWMEM;
				previnstr->opcode=op;
				previnstr->rdef=0;
				previnstr->csize++;
				previnstr->u1.immval=curinstr->u1.immval;
				thirdinstr->variant=OPBMEMLIT;
				thirdinstr->props|=LOADINSTR;
				thirdinstr->group=RWMEM;
				thirdinstr->opcode=nextinstr->opcode;
				thirdinstr->rdef=0;
				thirdinstr->rref&=(~(1<<curinstr->rd));
				thirdinstr->csize++;
				thirdinstr->u1.immval=nextinstr->u1.immval;
				BDeleteInstr(curinstr,0);
				BDeleteInstr(nextinstr,0);
				if (optimtrace!=0 && peepreport!=0)
					printf("\nPHOLE: Two ops on store bytes issued at %08X",previnstr);
				changes++;
				goto NextPass;
			}
		}
#endif

		/* Look for a register copy following a simple operation */
		/* where the two instructions can be merged into one LEA */
		/* The source reg must be dead after the move of course  */
		/* as must the flags reg which is not set by lea         */
		/* This can occur out of LOOP OPT reallocating locals to */
		/* integer registers. It is not common but can occur in  */
		/* 'hot' SPEC loops.                                     */

		if (op==MOV && curinstr->variant==OPRR && previ!=0 && previnstr->rd==curinstr->rs1 && 
			previnstr->u1.immval!=0x80000000 &&
			   (prevop==INC||prevop==DEC||
				((prevop==ADD||prevop==SUB) &&
			      (previnstr->variant==OPRSLIT||previnstr->variant==OPRLIT||previnstr->variant==OPEAXLIT)))) {
			BLiveSetAfterInstr(frag,curinstr,&rlive,&flive,&clive,&alive);
			if ((rlive&(257<<previnstr->rd))==0 && (clive&(1<<FLAGREG))==0) {
				curinstr->disp=previnstr->u1.immval;
				if (prevop==INC ||prevop==DEC)  curinstr->disp=1;
				if (prevop==DEC ||prevop==SUB)  curinstr->disp=-curinstr->disp;
				curinstr->opcode=LEA;
				curinstr->variant=OPRRM;
				if (curinstr->disp==0) {
					curinstr->csize=2;	 
					curinstr->rmbyte=0;
				} else if (-128<=curinstr->disp && curinstr->disp<=127) {
					curinstr->csize=3;	 
					curinstr->rmbyte=0x40;
				} else {
					curinstr->csize=6;	 
					curinstr->rmbyte=0x80;
				}

				curinstr->rref=256<<curinstr->rs1;
				curinstr->props&=(~COPYINSTR);
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: Two instrs merged into LEA at %08X\n",(unsigned)curinstr);
				}
				BDeleteInstr(previnstr,0);
				changes++;
				goto NextPass;
			}
		}

		/* Look for a register copy followed by a simple operatn */
		/* where the two instructions can be merged into one LEA */
		/* The flags  reg must be dead after the move of course  */
		/* This can occur out of LOOP OPT reallocating locals to */
		/* integer registers. It is not common but can occur in  */
		/* 'hot' SPEC loops.                                     */

		 if (previ!=0 && prevop == MOV && previnstr->variant==OPRR &&
			previnstr->rd==curinstr->rd && curinstr->u1.immval!=0x80000000 &&
			(op ==INC || op ==DEC          ||
			((op ==ADD || op ==SUB)      &&
			(curinstr->variant==OPRSLIT || curinstr->variant==OPRLIT 
			|| curinstr->variant==OPEAXLIT)))                       ) {
			BLiveSetAfterInstr(frag,curinstr,&rlive,&flive,&clive,&alive);
			if ((clive&(1<<FLAGREG))==0) {
				curinstr->disp=curinstr->u1.immval; curinstr->u1.immval=0;
				if (op ==INC || op ==DEC ) curinstr->disp=1;
				if (op ==DEC || op ==SUB ) curinstr->disp=-curinstr->disp;
				curinstr->opcode=LEA;
				curinstr->rs1=previnstr->rs1;
				curinstr->variant=OPRRM;
				if (curinstr->disp==0 && curinstr->rs1!=EBP  ) {
					curinstr->csize=2; curinstr->rmbyte=0;
				} else if (-128<=curinstr->disp && curinstr->disp<=127  ) {
					curinstr->csize=3; curinstr->rmbyte=0x40;
				} else {
					curinstr->csize=6; curinstr->rmbyte=0x80;
				}
				curinstr->rref=256<<curinstr->rs1;
				if (optimtrace!=0 && peepreport!=0 ) {
					printf("\nPHOLE: Two instrs coalesced into LEA at %08X\n",(unsigned)curinstr);
				}
				BDeleteInstr(previnstr,0);

				changes++;
				goto NextPass;
			}
		}

		/* look for LEA followed by a move and retatget the LEA */
		if (op==MOV && curinstr->variant==OPRR && previ!=0 && previnstr->rd==curinstr->rs1 &&
			prevop==LEA) {
			BLiveSetAfterInstr(frag,curinstr,&rlive,&flive,&clive,&alive);
			if ((rlive&(257<<previnstr->rd))==0) {
				previnstr->rd=curinstr->rd;
				previnstr->rdef=curinstr->rdef;
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: LEA amendend at %08X\n",(unsigned)previnstr);
				}
				BDeleteInstr(curinstr,0);

				changes++;
				goto NextPass;
			}
		}

		/* look for LEA without a SIB following and add and
		   try to combine into a single LEA                */
		if (op==LEA && (curinstr->privprops&SIBREQD)==0 &&
			previnstr!=NULL && previnstr->opcode==ADD &&
			previnstr->variant==OPRR && previnstr->rd==curinstr->rs1) {
			BLiveSetAfterInstr(frag,curinstr,&rlive,&flive,&clive,&alive);
			if ((rlive&(257<<curinstr->rs1))==0 || curinstr->rs1==curinstr->rd) {
				curinstr->csize++;
				curinstr->rs2=previnstr->rs1;
				curinstr->privprops|=SIBREQD;
				curinstr->sib=0;
				curinstr->rref|=(257<<curinstr->rs2);
				BDeleteInstr(previnstr,0);
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: LEA expanded at %08X\n",(unsigned)curinstr);
				}
				changes++;
				goto NextPass;
			}
		}

		/* Look for Integer results in the wrong register */
		/* Happens in FORTRAN because of epilogues */

		if (op==MOV && curinstr->variant==OPRR) {
			nextinstr=BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
			if (nextinstr!=NULL && (nextinstr->props&WRAPPERINSTR)!=0) {
				rref=curinstr->rref;
				rdef=curinstr->rdef;
				previnstr=BMachineInstr(curinstr->previnstr,PREVCHAIN);
				while (previnstr!=NULL) {
					if (previnstr->rdef==curinstr->rref) {
						previnstr->rd=curinstr->rd;
						previnstr->rdef=curinstr->rdef;
						if (optimtrace!=0 && peepreport!=0) {
							printf("\nPHOLE: PEEPHOLED INT RESULT GENERATOR AT %08X\n",(unsigned)previnstr);
							printf(" : %08X\n",(unsigned)curinstr);
						}
						BDeleteInstr(curinstr,0);
						BUpdateLiveRegs(frag);
						goto NextPass;
					}
					if ((((previnstr->rref|previnstr->rdef)&(rref|rdef)))!=0)   break ;
					previnstr=BMachineInstr(previnstr->previnstr,PREVCHAIN);
				}
			}
			/**/
			/* carry on from MOV substituting source for dest as long as it is safe      */
			/* this reduces dependencies and give scheduler more scope. However if       */
			/* we are assigning to a RegVar (including temporary ones allocated          */
			/* by loopopt) substitute dest for source since the regvar can be assumed    */
			/* to have a long life.                                                      */
			/**/
			anychanged=0;
			rd=curinstr->rd;	 
			rs1=curinstr->rs1;
			if (rd==rs1) {
				BDeleteInstr(curinstr,0);
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: Silly move deleted at %08X\n",(unsigned)curinstr);
				}
				goto NextPass;
			}
			if ((curinstr->privprops&REGVARASSN)!=0) {
				rd=rs1; 
				rs1=curinstr->rd;
			}
#if (OutputASSEMBLER==Negative)
			/* ESP may require changes in csize which are messy
			so only do this if ASSEMBLER can handle the problem */
			if (rd==ESP || rs1==ESP) goto NextPass;
#endif
			rref=1<<rs1;	 
			rdef=257<<rd;	 
			anyref=rref|rdef;
			fragaddr=(int)frag;
			while (nextinstr!=NULL) {
				if ((nextinstr->rref&rdef)!=0) 	/*%and nextinstr_rdef&(anyref)=0*/{
					changed=0;
					if (nextinstr->rd==rd && (nextinstr->rdef&anyref)==0 &&
						 nextinstr->variant!=OPONLY && 
						nextinstr->variant!=OPMEM && nextinstr->variant!=OPMEMLIT &&
						((nextinstr->privprops&BYTEREGOP)==0 || rs1<=3)) {
						/* byte loads and stores can only use first 4 regs   */
						nextinstr->rd=rs1;
						changed=1;
					}
					if (nextinstr->rs1==rd && nextinstr->variant!=OPONLY &&
						nextinstr->variant!=OPR && nextinstr->variant!=OPPLUSR &&
						((nextinstr->rdef&nextinstr->rref)==0 || nextinstr->opcode==LEA) &&
						((nextinstr->privprops&BYTEREGOP)==0 || rs1<=3)) {
						nextinstr->rs1=rs1;
						if (rs1==EBP && ((unsigned)nextinstr->rmbyte>>6)==0 && nextinstr->disp==0) {
							nextinstr->csize++;	 
							nextinstr->rmbyte|=0x40;
						}
						changed=1;
					}
					if (nextinstr->rs2==rd && (nextinstr->privprops&SIBREQD)!=0) {
						nextinstr->rs2=rs1;
						changed=1;
					}
					if (changed!=0) {
						if (((unsigned)nextinstr->rref>>8)!=0)  nextinstr->rref=(nextinstr->rref&(~rdef))|(rref<<8); 
						else 
							nextinstr->rref=(nextinstr->rref&(~rdef))|rref;
						anychanged=1;
						if (optimtrace!=0 && peepreport!=0) {
							printf("\nPHOLE: PEEPHOLED INT RESULT USER AT %08X\n",(unsigned)nextinstr);
						}
					}
				}
				/**/
				/* Check we have not set up a no-op                                          */
				/**/
				if (nextinstr->rd==nextinstr->rs1 && nextinstr->opcode==MOV && nextinstr->variant==OPRR) {
					BDeleteInstr(nextinstr,0);
					anychanged=1;
				}
				if (((nextinstr->rdef&anyref))!=0 || (nextinstr->props&ANYCALL)!=0)   break ;
				nextinstr=followinginstr2(&fragaddr,nextinstr->nextinstr,1);
			}
			if (anychanged!=0) {
				BUpdateLiveRegs(frag);
				if ((int)frag!=fragaddr)  BUpdateLiveRegs((struct fragfmt*)fragaddr);
				changes++;
			}
		}
		/**/
		/**/
NextPass:

		FirstPass=0;
		previnstr=curinstr;
		curi=(int)BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
	}
	if (optimtrace!=0 && peepreport!=0 && changes>0) {
		curinstr=frag->firstinstr;
		printf("\nFragment before repeat of cleanup\n");	 
		while (curinstr!=0) {
			p5printinstr(curinstr);
			curinstr=curinstr->nextinstr;
		}
	}
	if (changes>0)  goto again;

}	/* Cleanupfrag*/
/***/

static void CombineLitOps(struct fragfmt *frag) {
	/****************************************************************************/
	/** Search frag for sequences of ADD instructions with literal operands,   **/
	/** the same destination register and no intervening uses except in these  **/
	/** instructions. [ A bit unlikely, except in benchmarks. ]                **/
	/** Combine them into one instruction, assuming the combined literal still **/
	/** fits into 16 bits.                                                     **/
	/****************************************************************************/
	int r,rd,newval,op,opp;
	struct instrfmt * uses [32];	/* 0 or addr of instr which is reg's next use */
	struct instrfmt *instr,*use;

	for (r=0; r<=31; r++) {
		uses [r]=0;
	}

	instr=BMachineInstr(frag->lastinstr,PREVCHAIN);

	/* loop backwards through frag looking for ADD/SUB with literal opnd */

	while (instr!=NULL) {
		op=instr->opcode;

		if ((op==INC || op==DEC) || ((op==ADD || op==SUB) &&
			(instr->variant==OPRLIT || instr->variant==OPRSLIT))) {

			rd=instr->rd;
			if (uses [rd]!=NULL) {
				use=uses [rd];
				opp=use->opcode;
				if (op==INC) {op=ADD; instr->u1.immval=1;}
				if (op==DEC) {op=SUB; instr->u1.immval=1;}
				if (opp==INC) {opp=ADD; use->u1.immval=1;}
				if (opp==DEC) {opp=SUB; use->u1.immval=1;}
				if (op==opp)  newval=instr->u1.immval+use->u1.immval;
				if (op==SUB && opp==ADD)  newval=-(use->u1.immval-instr->u1.immval);
				if (op==ADD && opp==SUB)  newval=-(use->u1.immval-instr->u1.immval);
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: Combining two litops:");
					p5printinstr(instr);
					p5printinstr(use);
				}
				instr->privprops&=(~PARAMRECLAIM);
				instr->u1.immval=newval;
				instr->opcode=op;
				if ((-128<=newval)&&(newval<=127)) {
					instr->csize=3;	 
					instr->variant=OPRSLIT;	 
					instr->datasize=1;
				} else {
					instr->csize=6;	 
					instr->variant=OPRLIT;	 
					instr->datasize=4;
				}
				if (newval==1) {
					if (instr->opcode==ADD) instr->opcode=INC; else instr->opcode=DEC;
					instr->csize=1;
					instr->variant=OPPLUSR;
					instr->datasize=4;
				}
				if (optimtrace!=0 && peepreport!=0) {
					printf("\nPHOLE: Combined  litop=");
					if (newval==0)  printf("ZERO"); 
					else p5printinstr(instr);
					printf("\n");
				}
				if (newval==0)  BDeleteInstr(instr,0);
				BDeleteInstr(uses [rd],0);
				BUpdateLiveRegs(frag);
			}

			if (instr->rs1==rd)  uses [rd]=instr; 
			else {
				uses [rd]=NULL; 
				uses [instr->rs1]=NULL;
			}
		} else {
			for (r=0; r<=7; r++) {
				if (((instr->rref|instr->rdef)&(257<<r))!=0)  uses [r]=NULL;
			}

			if ((instr->props&JUMPINSTR)!=0) {
				for (r=0; r<=7; r++) {
					uses [r]=NULL;
				}
			}

		}

		instr=BMachineInstr(instr->previnstr,PREVCHAIN);
	}

}	/*CombineLitOps*/
/***/

static void RemoveLoads(struct fragfmt *frag) {
	/***************************************************************************/
	/** Attempt to match load/store instructions with loads from same location**/
	/** Such loads may be turned into copies in suitable circumstances.       **/
	/***************************************************************************/
	struct fragfmt *curfrag;
	struct instrfmt *instr,*nextinstr,*nextiterinstr,*previnstr;
	int overlap,movenow,movethen,curfragaddr;
	int stlen,streg1,ldreg1,rch,rused,xch,xused,bregs,var;

	static const int NOTSIMPLE=(((ANYCALL|JUMPINSTR)|LOADINSTR)|STOREINSTR)|BRANCH;
	static const int MEMORYINSTR=LOADINSTR|STOREINSTR;


	/* work backwards through fragment looking for memory instructions */
	nextiterinstr=BMachineInstr(frag->lastinstr,PREVCHAIN);

	while (nextiterinstr!=NULL) {
		instr=nextiterinstr;
		nextiterinstr=BMachineInstr(instr->previnstr,PREVCHAIN)	/* for next iteration */;

		if ((instr->props&MEMORYINSTR)==0) goto outerrepeat;
		if (optimtrace!=0 && peepreport!=0 && miscreport!=0) {
			printf("PHOLE: Testing");
			p5printinstr(instr);
		}

		/* have found a memory instruction: work forwards from here seeing */
		/* whether there is a load from the same location                  */

		nextinstr=BMachineInstr(instr->nextinstr,NEXTCHAIN);

		if ((instr->rdef&instr->rref)!=0)   continue ;
		/* avoid things like   ld  [%l2 +%l3], %l3  */
		if (instr->group!=INTLOAD && instr->group!=INTSTORE)   continue ;
		rused=0;
		rch=0;	/* record if any regs change */
		xused=0;
		xch=0;
		bregs=1<<instr->rs1;
		if ((instr->privprops&SIBREQD)!=0)  bregs|=1<<instr->rs2;	/* mask of baseregs*/

		curfrag=frag;
		while (nextinstr!=NULL) {


			if ((optimtrace!=0)&&(peepreport!=0)&&(miscreport!=0)) {
				printf("\nPHOLE: checking against");
				p5printinstr(nextinstr);
			}

			/* first update regs used or changed by instruction */

			if ((rch&bregs)!=0) break ;	/* base reg updated give up */

			if ((nextinstr->props&NOTSIMPLE)==0)  goto CheckNext;

			/* check for subsequent stores to same location */

			if ((nextinstr->props&STOREINSTR)!=0) {
				overlap=p5memoryoverlap(instr,nextinstr,1);
				if (overlap==MONO)  goto CheckNext;
				/* no memory overlap: can continue looking for loads */

				break ;	/* destinations may overlap: assume memory changed */

			}


			/* check for load now : can possibly modify or remove the load */

			if ((nextinstr->props&LOADINSTR)!=0) 	/*%and nextinstr_group=INT LOAD*/{
				overlap=p5memoryoverlap(instr,nextinstr,1);

				if (overlap==MOMAYBE)   break ;
				/* don't know what's happening: assume the worst */

				if (overlap==MONO) goto CheckNext;
				/* if no register interference then carry on looking */

				/* memory interference: see whether load can be modified */

				if (overlap!=MOEXACT || instr->datasize!=nextinstr->datasize)   break ;
				/* load is of different size : too complicated */

				stlen=instr->datasize;
				movenow=0;
				movethen=0;
				/**/
				/* move now #0 if the current load can be replaced by a move                 */
				/* move then # 0 if a move can be inserted after the load-store              */
				/*               held in instr                                               */
				/* there are intermediate case where a move can be inserted (one day ?)      */
				/**/

				if (stlen>=4  ||
					(instr->opcode==nextinstr->opcode &&
					(instr->opcode==LBU || instr->opcode==LB || 
					   instr->opcode==LHU|| instr->opcode==LH))) {

					/* deal with whole-register cases */

					if (nextinstr->group!=INTLOAD) 	/* add to reg etc*/{
						if ((((1<<instr->rd)&rch))==0 && 
							(nextinstr->privprops&VOLATILELOC)==0 &&
							nextinstr->variant==OPRRM) {
							nextinstr->variant=OPRR;
							nextinstr->csize=1+ARCH(opcodesize(nextinstr->opcode,OPRR));
							nextinstr->area=0;
							nextinstr->u0.offset=0;
							nextinstr->rs1=instr->rd;
							nextinstr->rref=(1<<nextinstr->rd)|(1<<nextinstr->rs1);
							nextinstr->privprops&=(~FIXEDINSTR);
							nextinstr->props&=~LOADINSTR;
							if (optimtrace!=0 && peepreport!=0) {
								printf("\nPHOLE: using register copy:");
								p5printinstr(nextinstr);
								printf("\n");
							}
							BUpdateLiveRegs(curfrag);
						}
					} else if (instr->rd==nextinstr->rd) {

						if (instr->rd<=7 && ((1<<instr->rd)&rch)!=0)   break ;
						/* reloading same register(s): delete the load instr */
						/* since the old copy has not been updated           */
						if (optimtrace!=0 && peepreport!=0) {
							printf("\nPHOLE: DELETING REDUNDANT LOAD INSTRUCTION:");
							p5printinstr(nextinstr);
							printf("\n");
						}

						BDeleteInstr(nextinstr,0);
						BUpdateLiveRegs(frag);
						if (frag!=curfrag)  BUpdateLiveRegs(curfrag);
						nextinstr->rref=0;
						nextinstr->rdef=0;
						nextinstr->fref=0;
						nextinstr->fdef=0;
						goto CheckNext;

					} else {

						/* loading different registers: change load to copy */

						streg1=instr->rd;
						ldreg1=nextinstr->rd;

						if (streg1<=7 && ((1<<streg1)&rch)==0)  movenow=1;
						/* if moving early must beware of Beta reads!  */
						if (ldreg1<=7 && (((257<<ldreg1)&(rch|rused)))==0 && 
							(frag==curfrag || ((257<<ldreg1)&frag->rout)==0))  movethen=1;
						if ((movenow|movethen)==0)   break ;

						/* change load instruction to a register copy */

						nextinstr->opcode=MOV;
						nextinstr->rd=ldreg1;
						nextinstr->rs1=streg1;
						nextinstr->rs2=0;
						nextinstr->u1.immval=0;
						nextinstr->datasize=0;
						nextinstr->rref=1<<streg1;
						nextinstr->rdef=257<<ldreg1;
						nextinstr->props=((nextinstr->props&(~LOADINSTR))|COPYINSTR)|DESTROYABLE;
						nextinstr->privprops=nextinstr->privprops&(~(SYMBOLICACCESS|FRAMEACCESS));
						nextinstr->area=-1;
						nextinstr->variant=OPRR;
						nextinstr->csize=2;
						nextinstr->domain=0;
						nextinstr->group=instrgroup [nextinstr->opcode];


						if (optimtrace!=0 && peepreport!=0) {
							printf("\n");
							printf(bannerline);
							printf("\nPHOLE: CHANGING LOAD TO REGISTER COPY Of:");
							phex((int)instr);
							p5printinstr(nextinstr);
							printf("\n");
							printf("\n");
						}

						rch|=nextinstr->rdef;
						rused|=nextinstr->rref;
						xch|=nextinstr->fdef;
						xused|=nextinstr->fref;
						/* if no register interference can carry on */

						if ((movethen!=0)&&(movenow==0)) {
							previnstr=nextinstr->previnstr;
							BMoveAfter(curfrag,frag,nextinstr,instr);
							if (previnstr==NULL)  previnstr=frag->lastinstr;
							nextinstr=previnstr;
						}

						BUpdateLiveRegs(frag);
						if (frag!=curfrag)  BUpdateLiveRegs(curfrag);

						if (movethen!=0)   break ;
					}


				} else {
					/* part-register cases */

					/* maybe someday ...   */
					var=nextinstr->variant;
					if (nextinstr->opcode!=CMP && nextinstr->opcode!=TEST)   break ;
					if (var!=OPMEMLIT && var!=OPRRM)   break ;
					/**/
					/* adjust instruction size                                                   */
					/**/
					if ((nextinstr->privprops&SIBREQD)!=0)  nextinstr->csize=nextinstr->csize-
					1;
					if (((nextinstr->privprops&FIXEDINSTR)!=0)||((nextinstr->disp<-128)||(nextinstr->disp>127))) {
						nextinstr->csize=nextinstr->csize-4;
					} else {
						if (nextinstr->disp!=0)  nextinstr->csize=nextinstr->csize-1;
					}
					/**/
					/* adjust variant and flags                                                  */
					/**/
					if (var==OPMEMLIT) {
						nextinstr->variant=OPRLIT;
						if ((nextinstr->opcode==CMP)&&((-128<=nextinstr->u1.immval)&&(nextinstr->u1.immval<=127)))  nextinstr
						->variant=OPRSLIT;
						nextinstr->rd=instr->rd;
						nextinstr->rref=1<<nextinstr->rd;
					} else {
						nextinstr->variant=OPRR;
						nextinstr->rs1=instr->rd;
						nextinstr->rref=(1<<nextinstr->rd)|(1<<nextinstr->rs1);
					}
					nextinstr->privprops=nextinstr->privprops&(~(FIXEDINSTR|SIBREQD));
					nextinstr->props=nextinstr->props&(~LOADINSTR);
					nextinstr->area=-1;
					nextinstr->disp=-1;
					if (optimtrace!=0 && peepreport!=0) {
						printf("\nPHOLE: CHANGING LOAD TO USE REGISTER at:");
						p5printinstr(nextinstr);
						printf("\n");
					}
				}

			}


			if ((nextinstr==NULL)||((nextinstr->props&(ANYCALL|JUMPINSTR))!=0))   break ;	/* can't look beyon
			    d calls, etc */

CheckNext:

			rch|=nextinstr->rdef;
			rused|=nextinstr->rref;
			xch|=nextinstr->fdef;
			xused|=nextinstr->fref;


			nextinstr=BMachineInstr(nextinstr->nextinstr,NEXTCHAIN);
			if (nextinstr==NULL) {
				curfragaddr=(int)curfrag;
				nextinstr=followinginstr2(&curfragaddr,nextinstr,1)	/* into next frag
				    if safe)*/;
				if (nextinstr!=NULL)  curfrag=(struct fragfmt*)(curfragaddr);
			}

		}

outerrepeat:;
	}
}	/* RemoveLoads */
/***/
static void RemoveDeadStores(struct fragfmt *frag) {
	/***************************************************************************/
	/** Attempt to remove stores into stack frames on exit paths              **/
	/***************************************************************************/
	struct instrfmt *instr,*nextinstr,*followinstr;
	int overlap;


	/* work backwards through fragment looking for memory instructions */
	followinstr=BMachineInstr(frag->lastinstr,PREVCHAIN);

	while (followinstr!=NULL) {
		instr=followinstr;
		followinstr=BMachineInstr(instr->previnstr,PREVCHAIN)	/* for next iteration */;

		if ((instr->props&ANYCALL)!=0)  return;
		if ((instr->props&STOREINSTR)!=0 && (instr->props&WRAPPERINSTR)==0 &&
		    instr->area==STACK && !instr->cdef) {


			if (optimtrace!=0 && peepreport!=0 && miscreport!=0) {
				printf("PHOLE: Deadstore Testing ");	 
				p5printinstr(instr);
			}

			/* have found a store instruction: work forwards from here seeing */
			/* whether there is a load from the same location                  */

			nextinstr=BMachineInstr(instr->nextinstr,NEXTCHAIN);


			while (nextinstr!=NULL) {

				if ((nextinstr->props&LOADINSTR)==0)  goto CheckNext;

				if (optimtrace!=0 && peepreport!=0 && miscreport!=0) {
					printf("\nPHOLE: checking against ");	 
					p5printinstr(nextinstr);
				}


				/* check for load now : can possibly modify or remove the load */

				overlap=p5memoryoverlap(instr,nextinstr,0);

				if (overlap==MONO) {
					/* if no register interference then carry on looking */

					goto CheckNext;

				}

				if (optimtrace!=0 && peepreport!=0 && miscreport!=0) 
					printf("\nPHOLE: memory interference %2d %2d",
						instr->datasize,nextinstr->datasize);
				goto NextStore;
CheckNext:

				nextinstr=BMachineInstr(nextinstr->nextinstr,NEXTCHAIN);

			}

			/**/
			/* Have checked all loads after "instr" no intereference found               */
			/* can delete the store                                                      */
			/**/
			if (optimtrace!=0 && peepreport!=0) 
				printf("\nPHOLE: Dead store deleted  %08X\n",(unsigned)instr);	 
			BDeleteInstr(instr,1);
			BUpdateLiveRegs(frag);
		}

NextStore:;
	}

}	/* RemoveDeadStores */
/***/

/***/

static void Doubledefs(struct fragfmt *frag) {
	/*************************************************************************/
	/** Looks for registers which are redfined without being used           **/
	/** If the first definition has no side effects (ie sets CC) then       **/
	/** delete the first definition. At the frag end delete all defns       **/
	/** of unused registers that are not 'live' in subsequent frags.        **/
	/*************************************************************************/
	int rref,rdef,fref,fdef,cref,cdef;
	int anychanged;
	int changes,opcode,rd,rlive,flive,clive,dlive;
	struct instrfmt *curinstr,*nextinstr;
	static const int IPARAMREGS=1<<EBP;	/* Bit mask of integer parameter regs + displ reg*/
	/* Enter will read EBP hencethis is a param reg for IMP at least */
	static const int FPARAMREGS=0x0;	/* do for Float params */

	anychanged=0;
again:	/* one deletion can lead to a chain*/

	changes=0;

	nextinstr=BMachineInstr(frag->firstinstr,NEXTCHAIN);
	while (nextinstr!=NULL) {
		curinstr=nextinstr;
		nextinstr=BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
		opcode=curinstr->opcode;
		rdef=curinstr->rdef&0xFFFF;
		fdef=curinstr->fdef;
		rref=curinstr->rref&0xFFFF;
		fref=curinstr->fref;
		cdef=curinstr->cdef;
		cref=curinstr->cref;
		rd=curinstr->rd;



		if ((curinstr->props&ANYCALL)!=0) {
			/**/
			/* a call with no delay slot effectively read any param regs and defines all volatile regs*/
			/* A D-S is more compilcated but this is first called before D-S filling     */
			/**/
			rref=IPARAMREGS|curinstr->rref;
			/* rdefs as defined in instruction */
			/**/
			/* The stackpointer will be reset so the value will not be lost even tho it is not*/
			/* a callee save reg                                                         */
			/*  Hence amendmments to CALLEE SAVED REGS above                             */
			/**/
			fref=FPARAMREGS;	 
			fdef=~CALLEESAVEDFREGS;
		}
		/**/
		/**/
		/* step3 record any definitions for later reference avoiding delay slot instrs*/
		/* which might not be executed and any instruction that defines more than a  */
		/* single register or regpair                                                */
		/**/
		if ((curinstr->props&(ANYCALL|JUMPINSTR|FRAMEMODIFY|WRAPPERINSTR|STOREINSTR))!=0)   continue ;
		if ((curinstr->props&DESTROYABLE)==0)   continue ;
		if (fdef!=0) continue ;
		if (nextinstr!=NULL && ((nextinstr->rref&rdef)!=0 ||
			(nextinstr->cref&cdef)!=0)) continue;
		BLiveSetAfterInstr(frag,curinstr,&rlive,&flive,&clive,&dlive);
		if ((rdef&rlive)==0 && (cdef&clive)==0 ) {
			if (optimtrace!=0 && peepreport!=0)
				printf("DDEFS: Instruction has no live oputs %08X\n",(unsigned)curinstr);
			/* FSTP is dead on returns but this leaves rubbish on stack!*/
			if ((cdef&(1<<FSTP))==0) {
				BDeleteInstr(curinstr,0);
				anychanged++;
			}
		}

	}
	/**/
	/* if there are still unused definitions then check whether they are unused  */
	/* beyond this fragment (by looking at frag's liveness info)                 */
	/**/
	if (anychanged!=0) {
		BUpdateLiveRegs(frag);
		anychanged=0;
		goto again;
	}
	return;
}	/*Doubledefs*/
/***/
static void RecheckStackStores(struct fragfmt *procfrag) {
	/*************************************************************************/
	/** After the peepholing and load reduction some more stack stores      **/
	/** might be redundant. Check and remove                                **/
	/*************************************************************************/
	int i,offset,j;
	struct fragfmt *frag,*nextfrag;
	struct instrfmt *instr,*nextinstr;

	for (i=1; i<=256; i++	/* Leaving 0 which has addrtaken bit */)  StackSTflags [i]=StackSTflags [i]&4;

	nextfrag=procfrag;
	while (nextfrag!=NULL) {
		frag=nextfrag;
		nextfrag=frag->nextfrag;
		nextinstr=BMachineInstr(frag->firstinstr,NEXTCHAIN);
		while (nextinstr!=NULL) {
			instr=nextinstr;
			nextinstr=BMachineInstr(instr->nextinstr,NEXTCHAIN);
			if ((instr->props&WRAPPERINSTR)==0 && 
				(instr->props&(LOADINSTR|STOREINSTR))!=0 && 
				instr->area==STACK) {
				offset=(unsigned)((-instr->u0.offset)+3)>>2;
				if (1<=offset && offset<=256) {
					j=instr->datasize;
					do {
						if ((instr->props&LOADINSTR)!=0 && instr->opcode!=POP)
							 StackSTflags [offset]|=2;
						if ((instr->props&STOREINSTR)!=0 && instr->opcode!=PUSH)
							  StackSTflags[offset]|=1;
						offset--;
						j-=4;
					} while (j>0) ;
				}
			}
		}
	}
	for (i=1; i<=256; i++) {
		if (StackSTflags [i]==1)  goto part2;
	}
	return;	/* no deletable stores                                             */
part2:

	nextfrag=procfrag;
	while (nextfrag!=NULL) {
		frag=nextfrag;
		nextfrag=frag->nextfrag;
		nextinstr=frag->firstinstr;
		while (nextinstr!=NULL) {
			instr=nextinstr;
			nextinstr=instr->nextinstr;
			if ((instr->props&WRAPPERINSTR)==0 && (instr->props&STOREINSTR)!=0 && instr->area==STACK) {
				offset=(unsigned)((-instr->u0.offset)+3)>>2;
				if (1<=offset && offset<=256) {
					if (StackSTflags [offset]==1 &&
					(instr->datasize<=4 ||
					(instr->datasize<=8 && StackSTflags[offset-1]==1)) &&
					instr->opcode!=FISTP && instr->opcode!=FSTPm && instr->opcode!=FSTPd) {
						if (optimtrace!=0 && peepreport!=0) {
							printf("PHOLE: Store deleted after rechk %08X\n",(unsigned)instr);	 
						}
						BDeleteInstr(instr,1);
						BUpdateLiveRegs(frag);
					}
				}
			}
		}
	}
}	/* rechech stack stores */
/***/
static void makepreamble(struct fragfmt *prevfrag,int preptr,struct instrfmt *preinstrs) {
	/*************************************************************************/
	/** Add the instrs in the preamble to the back of prevfrag              **/
	/*************************************************************************/
	struct fragfmt *tempfrag,*firstfrag,*i,*j;
	struct instrfmt *newinstr;
	int k;
	/**/
	/* if the preamble is to go into an empty frag there is red tape work        */
	/**/
	firstfrag=prevfrag->final;
	if (firstfrag!=prevfrag) {
		prevfrag->props=(prevfrag->props|FALLENINTO)|FALLSTHROUGH;
		prevfrag->uses=1;
		prevfrag->rin=firstfrag->rin;
		prevfrag->rout=firstfrag->rout;
		prevfrag->fin=firstfrag->fin;
		prevfrag->fout=firstfrag->fout;
		prevfrag->cin=firstfrag->cin;
		prevfrag->cout=firstfrag->cout;
		i=prevfrag;
		j=prevfrag->final;
		prevfrag->final=i;
		tempfrag=prevfrag;
		do {
			tempfrag=tempfrag->prevfrag;
			if (tempfrag==NULL)   break ;
			if (tempfrag->final==j)  tempfrag->final=i;
		} while (1) /* FOR EVER */;
	}
	for (k=0; k<=	/* At endof frag */preptr-1; k++) {
		newinstr=BInsertInstr(prevfrag,NULL);
		BCopyInstr(&preinstrs [k],newinstr);
	}
}	/*makepreamble */
static void makepostamble(struct fragfmt *frag,int postptr,struct instrfmt *postinstrs) {
	/*************************************************************************/
	/** Add the instrs in the postamble to the front of frag                **/
	/*************************************************************************/
	int k;
	struct fragfmt *final;
	struct instrfmt *newinstr;
	final=frag->final;
	if (final!=frag) {
		frag->props=(final->props&FALLENINTO)|FALLSTHROUGH;
		frag->final->props|=FALLENINTO;
		frag->uses=1;
		frag->rin=final->rin;
		frag->rout=final->rout;
		frag->fin=final->fin;
		frag->fout=final->fout;
		frag->cin=final->cin;
		frag->cout=final->cout;
		frag->final=frag;
	}
	for (k=0; k<=postptr-1; k++)	/* at front of frag*/ {
		newinstr=BInsertInstr(frag,frag->firstinstr);
		BCopyInstr(&postinstrs [k],newinstr);
	}
}	/* makepostamble*/
/***/
static void makepush(struct instrfmt *instr,int rd) {
	/*************************************************************************/
	/** generate a PUSH for the preamble                                    **/
	/*************************************************************************/

	memset(instr,0,sizeof( struct instrfmt));
	instr->opcode=PUSH;
	instr->rd=rd;
	instr->group=SPECIAL;
	instr->datasize=4;
	instr->csize=1;
	instr->props=DESTROYABLE|STOREINSTR;
	instr->variant=OPPLUSR;
	instr->rref=(1<<rd)|(256<<ESP);
	instr->rdef=257<<ESP;
	if (optimtrace!=0 && peepreport!=0) {
		printf("LOOP: Reg spilled to improve loop ");
		p5printregisters(1<<rd,0,0);
		printf("\n");
	}
}	/*make push*/
/***/
static void makefpop(struct instrfmt *instr) {
	/*************************************************************************/
	/** generate a POP of the Fstack for the postamble                      **/
	/*************************************************************************/

	memset(instr,0,sizeof( struct instrfmt));
	instr->opcode=FSTPd;
	instr->rd=LASTFREG;
	instr->rs1=LASTFREG;
	instr->group=FPSTORE;
	instr->csize=2;
     /* instr->props=DESTROYABLE; */   /* FP stack must always be tidied */
	instr->variant=FOPPLUSR;
	instr->fref=(1<<LASTFREG)&7;
	instr->fdef=instr->fref;
	instr->cref=(1<<FPSCR)|(1<<FSTP);
	instr->cdef=1<<FSTP;
}	/*make pop */
/***/
static void makepop(struct instrfmt *instr,int rd) {
	/*************************************************************************/
	/** generate a POP for the postamble                                    **/
	/*************************************************************************/

	memset(instr,0,sizeof( struct instrfmt));
	instr->opcode=POP;
	instr->rd=rd;
	instr->group=SPECIAL;
	instr->datasize=4;
	instr->csize=1;
	instr->props=DESTROYABLE|LOADINSTR;
	instr->variant=OPPLUSR;
	instr->rref=1<<ESP;
	instr->rdef=(257<<rd)|(257<<ESP);
}	/*make pop */
/***/
static void mostloaded(int *loadads,int *storeads,int *lmask,int *smask,int postvalid,int defmask) {
	/*************************************************************************/
	/** Find the most loaded or referenced integer that is not liable to be **/
	/** updated on the fly and that is not involved in FP operations        **/
	/*************************************************************************/
	struct instrfmt *instr,*nextinstr;
	int nloads,nstores,i,j,k,cumloads,res;
	int count [31+1];
	int lmasks [31+1];
	int smasks [31+1];

	nloads=loadads [0];
	nstores=storeads [0];
	cumloads=0;
	/**/
	/* traverse the list of loads checking for exact matches and no nasties      */
	/**/
	for (i=1; i<=nloads; i++) {
		count [i]=-1;	 
		lmasks [i]=0;	 
		smasks [i]=0;
		if (((1<<i)&cumloads)!=0)   continue ;	/* already processed */
		instr=(struct instrfmt*)(loadads [i]);
		if (instr->group!=INTLOAD)   continue ;	/* First one must be a load */
		if (instr->rref&defmask) continue;
		count [i]=1;
		for (j=i+1; j<=nloads; j++) {
			nextinstr=(struct instrfmt*)(loadads [j]);
			res=p5memoryoverlap(instr,nextinstr,0);
			if (res==MONO)   continue ;
			if ((res==MOEXACT)&&((nextinstr->fref|nextinstr->fdef)==0)) {
				count [i]=count [i]+1;
				lmasks [i]=lmasks [i]|(1<<j);
				cumloads|=1<<j;
			} else {
				count [i]=-1;
				break ;
			}
		}
		if (count [i]<0)   continue ;
		/**/
		/* check for any nasties in the earlier part of the loop                     */
		/**/
		for (j=1; j<=i-1; j++) {
			nextinstr=(struct instrfmt*)(loadads [j]);
			res=p5memoryoverlap(instr,nextinstr,0);
			if (res!=MONO) {
				count [i]=-1;  
				break ;
			}
		}
		/**/
		/* check out the stores                                                      */
		/**/
		for (j=1; j<=nstores; j++) {
			nextinstr=(struct instrfmt*)(storeads [j]);
			res=p5memoryoverlap(instr,nextinstr,0);
			if (res==MONO)   continue ;
			if ((res==MOEXACT)&&(postvalid>0)&&((instr->privprops&BYTEREGOP)==0)&&(instr->datasize!=1)&&((nextinstr
			    ->fref|nextinstr->fdef)==0)) {
				count [i]=count [i]+1;
				smasks [i]=smasks [i]|(1<<j);
			} else {
				count [i]=-1;
				break ;
			}
		}
	}
	/**/
	/* find the most used (could be none)                                        */
	/**/
	j=0;	 
	k=0;
	for (i=1; i<=nloads; i++) {
		if (count [i]>k) {
			j=i; 
			k=count [i];
		}
	}
	if (k<=1) {
		*lmask=0;	 
		*smask=0;	 
		return;
	}

	*lmask=lmasks [j]|(1<<j);
	*smask=smasks [j];
	if (optimtrace!=0 && peepreport!=0) {
		printf("LOOP: most used valid load %08X usecount=%2d",loadads [j],k);	 
		printf(" lmask=%x smask=%x\n",*lmask,*smask);	 
	}
}	/*most loaded*/
static void updateinstr(struct instrfmt *instr,int xtrareg) {
	/*************************************************************************/
	/** alter instr so a reference to xtrareg replabes the store referenc   **/
	/*************************************************************************/
	int variant,group,opcode;
	variant=instr->variant;
	group=instr->group;
	opcode=instr->opcode;
	switch (variant) {
	default:
		Mabort(707);

	case OPRRM:
		/* rem& memeory to reg-reg                                                  */
		if (group==INTLOAD) {
			instr->variant=OPRR;
			instr->csize=2;
			instr->group=INTOPSu;
			instr->rs1=xtrareg;
			instr->opcode=MOV;
			instr->props=(instr->props&(~LOADINSTR))|COPYINSTR;
			instr->privprops&=~(BYTEREGOP|FIXEDINSTR);
			instr->datasize=4;
			instr->u2.prefixes [osprefix]=0;
			instr->rmbyte=0xC0;
			instr->rref=1<<xtrareg;
			return;
		}
		if ((group==INTOPS)||(group==INTOPSu)) {
			instr->variant=OPRR;
			instr->csize=2;
			if (opcode==IMUL)  instr->csize=3;
			instr->rs1=xtrareg;
			instr->props&=~LOADINSTR;
			instr->privprops&=~FIXEDINSTR;
			instr->rmbyte=0xC0;
			instr->rref=(1<<xtrareg)|(1<<instr->rd);
			instr->datasize=4;
			instr->u2.prefixes [osprefix]=0;
			return;
		}
		Mabort(727);

	case OPRMR:
		/* Store instrs and add to stores                                           */
		if (group==INTSTORE) {
			instr->variant=OPRR;
			instr->csize=2;
			instr->group=INTOPSu;
			instr->opcode=MOV;
			instr->props=(instr->props&(~STOREINSTR))|COPYINSTR;
			instr->privprops=(instr->privprops&(~FIXEDINSTR))|REGVARASSN;
			instr->rmbyte=0xC0;
			instr->rs1=instr->rd;
			instr->rd=xtrareg;
			instr->rdef=257<<xtrareg;
			instr->rref=1<<instr->rs1;
			instr->datasize=4;
			instr->u2.prefixes [osprefix]=0;
			return;
		}
		Mabort(737);

	case OPMEMLIT:
		/* move lit to store or cmp lit to store                                    */
		instr->rmbyte=0xC0;
		if (instr->opcode==MOV) {
			instr->csize=6;
			instr->variant=OPRLIT;
		} else {
			if ((-128<=instr->u1.immval)&&(instr->u1.immval<=127)) {
				instr->csize=3;
				instr->variant=OPRSLIT;
			} else {
				instr->csize=6;
				instr->variant=OPRLIT;
			}
		}
		instr->rd=xtrareg;
		instr->props&=~(LOADINSTR|STOREINSTR);
		instr->privprops=(instr->privprops&(~FIXEDINSTR))|REGVARASSN;
		if (instr->opcode==MOV) {
			instr->rdef=257<<instr->rd;
			instr->rref=0;
		} else {
			instr->rdef=0;
			instr->rref=1<<instr->rd;
		}

		instr->u2.prefixes [osprefix]=0;
		instr->datasize=4;
		return;
	}	/* end of case */
}	/*update instr*/
/***/
static void arrangeloads(int *loadads,int *storeads,int lmask,int smask,int xtrareg,struct instrfmt
*preinstrs,struct instrfmt *postinstrs,int *preptr,int *postptr) {
	/*************************************************************************/
	/** Arrange to Load a variable into xtrareg and change all itsreferences**/
	/** from r-m to rform. The load goes into the preamble and it may need  **/
	/** a corresponding store int the postamble                             **/
	/*************************************************************************/
	int i;
	struct instrfmt *ldinstr,*instr,*stinstr;
	/**/
	/* the first instruction must currently be a load                            */
	/**/
	i=1;
	while (((1<<i)&lmask)==0)  i++;
	ldinstr=(struct instrfmt*)(loadads [i]);
	instr=&preinstrs [*preptr];
	*preptr+=1;
	BCopyInstr(ldinstr,instr);
	/**/
	/* amend instr to load xtrareg                                               */
	/**/
	instr->rd=xtrareg;
	instr->rdef=257<<xtrareg;
	/**/
	/* make corresponding store instr unless no stores in loop                   */
	/**/
	if (smask!=0) {
		stinstr=&postinstrs [*postptr];
		*postptr+=1;
		BCopyInstr(instr,stinstr);
		stinstr->rref=stinstr->rref|(1<<xtrareg);
		stinstr->rdef=0;
		stinstr->variant=OPRMR;
		stinstr->props=(stinstr->props&(~LOADINSTR))|STOREINSTR;
		if (stinstr->datasize==1)  stinstr->opcode=SB; 
		else if (stinstr->datasize==2)  stinstr->opcode=SH; 
		else 
			stinstr->opcode=ST;

		stinstr->csize=(instr->csize-ARCH(opcodesize(instr->opcode,instr->variant)))+ARCH(opcodesize(stinstr->opcode
		    ,stinstr->variant));
	}

	for (i=1; i<=31; i++) {
		if (((1<<i)&lmask)!=0) {
			instr=(struct instrfmt*)(loadads [i]);
			updateinstr(instr,xtrareg);
		}
		if (((1<<i)&smask)!=0) {
			instr=(struct instrfmt*)(storeads [i]);
			updateinstr(instr,xtrareg);
		}
	}
}	/*arrange loads */
/***/
/***/
static int countjumpstolab(int labx) {
	/*************************************************************************/
	/**  cycles through the frags counting references to labx               **/
	/*************************************************************************/
	struct fragfmt *frag;
	int n;
	n=0;	 
	frag=PI->procfrag;
	while (frag!=NULL) {
		if (labx==frag->labref)  n++;
		frag=frag->nextfrag;
	}
	if (optimtrace!=0 && peepreport!=0) {
		printf("Countjumps reports %2d to lab with index %5d\n",n,labx);	 
	}
	return n;
}
/***/
static int unsafeoverlaps(struct instrfmt *instr,int nstores,int *storeads) {
	static const int MAXSTORES=31;
	int i,res;
	if (nstores>=MAXSTORES)  return MOYES;
	for (i=1; i<=nstores; i++) {
		res=p5memoryoverlap(instr,(struct instrfmt *)(storeads [i]),1);
		if (res!=MONO)  return res;
	}
	return MONO;
}
/***/
static void loopopt(struct fragfmt *firstfrag,struct fragfmt *lastfrag,int exitlabx) {
	/*************************************************************************/
	/** Attempts to move loop invariant register loads to preamble.         **/
	/** Can allow for a single conditional path in parts of the loop.       **/
	/*************************************************************************/
	struct instrfmt *curinstr,*nextinstr,*newinstr;
	struct fragfmt *frag,*prevfrag,*tempfrag,*sideexitfrag,*postfrag;
	int usemask,usebeforedef,validdef,defmask,fdefmask,storeseen,nfpops,i,k,deadregs,moved,op,curi,nexti
	,singledef,condpath,bit,nstores,nloads,validaccess,xtrareg,liveexitr,dumpableregs,lmask,smask;
	struct lrecfmt *lrec;
#define MAXHOISTS 30
	struct instrfmt preinstrs [MAXHOISTS+1];
	struct instrfmt postinstrs [MAXHOISTS+1];
	int preptr,postptr,postvalid;
	static const int maxstores=31;
	static const int usableregs=((((((1<<EBP)|(1<<EAX))|(1<<EBX))|(1<<ECX))|(1<<EDX))|(1<<ESI))|(1<<EDI
	    );
	int defs [7+1];
	int storeads [31+1];
	int loadads [31+1];
	int fpops [31+1];

again:

	postptr=0;	 
	preptr=0;	 
	postvalid=1;
	usemask=0;	 
	usebeforedef=0;	 
	nstores=0;	 
	nloads=0;
	validdef=0;	 
	storeseen=0;	 
	nfpops=0;
	moved=0;	 
	defmask=0;	 
	fdefmask=0;
	for (i=0; i<=7; i++)  defs [i]=0;
	postfrag=lastfrag->nextfrag;
	postfrag=postfrag->final;
	if (exitlabx!=0) {
		lrec=BLabRecAd(exitlabx);
		sideexitfrag=lrec->frag;
		sideexitfrag=sideexitfrag->final;
		if (!((sideexitfrag->uses==1)||((sideexitfrag->uses==2)&&((int)postfrag==(int)sideexitfrag)&&((sideexitfrag
		    ->props&FALLENINTO)!=0))))  postvalid=0;	/*can not add a postamble*/
	}
	if (!(((postfrag->props&FALLENINTO)==0)||(((postfrag->props&FALLENINTO)!=0)&&(postfrag->uses==1))||(((postfrag
	    ->props&FALLENINTO)!=0)&&(postfrag->uses==2)&&(exitlabx!=0)&&((int)postfrag==(int)sideexitfrag))))
		postvalid=0;
	/**/
	/* there is one more possibility. There might be an empty frag right after   */
	/* the final frag                                                            */
	/**/
	if ((postvalid==0)&&(exitlabx!=0)&&(lrec->frag==lastfrag->nextfrag)) {
		tempfrag=lrec->frag;
		if ((tempfrag->final!=tempfrag)&&(countjumpstolab(exitlabx)==1)) {
			sideexitfrag=tempfrag; 
			postfrag=tempfrag; 
			postvalid=1;
		}
	}

        /* If there is no exit label we can establish a valid postamble frag by brute force */

	if (postvalid==0 && exitlabx==0) {
		tempfrag=BObtainFrag();
		tempfrag->prevfrag=lastfrag->final;
		tempfrag->nextfrag=lastfrag->final->nextfrag;
		tempfrag->nextfrag->prevfrag=tempfrag;
		tempfrag->prevfrag->nextfrag=tempfrag;
		tempfrag->final=tempfrag->nextfrag->final;
		tempfrag->rout=tempfrag->final->rout;
		tempfrag->fout=tempfrag->final->fout;
		tempfrag->cout=tempfrag->final->cout;
		tempfrag->rin=tempfrag->rout;
		tempfrag->fin=tempfrag->fout;
		tempfrag->cin=tempfrag->cout;
		postfrag=tempfrag; postvalid=1;
	}

	prevfrag=firstfrag->prevfrag;
	frag=firstfrag;
	do {
		curi=(int)BMachineInstr(frag->firstinstr,NEXTCHAIN);
		while (curi!=0) {
			curinstr=(struct instrfmt*)(curi);
			nexti=(int)BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
			nextinstr=(struct instrfmt*)(nexti);
			op=curinstr->opcode;
			if ((curinstr->props&ANYCALL)!=0)  return;
			if ((curinstr->props&STOREINSTR)!=0) {
				if (curinstr->area==-1)  bit=-1; 
				else if (curinstr->area>30)  bit=0x80000000; 
				else bit=1<<curinstr
				->area;

				storeseen|=bit;	/* storeseen a mask of areas */
				if (nstores>=maxstores)  return;
				nstores++;
				storeads [nstores]=curi;
			}
			if ((curinstr->props&LOADINSTR)!=0) {
				if (nloads>=maxstores)  return;
				nloads++;
				loadads [nloads]=curi;
			}

			if ((curinstr->fref|curinstr->fdef)!=0) {
				nfpops++;
				if (nfpops<=maxstores)  fpops [nfpops]=curi;
			}
			usemask|=curinstr->rref;
			usebeforedef|=curinstr->rref&(~defmask);
			defmask|=curinstr->rdef;
			fdefmask|=curinstr->fdef;
			if (PI->privprops&NOTLEAFRT) {
				i=~(257<<EBP);
			} else {
				i=~(257<<ESP);
			}
			if (((curinstr->rref&i)|curinstr->fref|(curinstr->cref&(1<<FCCBIT)))==0)
			  validdef|=curinstr->rdef;
			if (curinstr!=0) {
				for (i=0; i<=7; i++) {
					if (((1<<i)&curinstr->rdef)!=0)  defs [i]=defs [i]+1;
				}
			}
			curi=nexti;
		}
		if ((int)frag==(int)lastfrag)   break ;
		frag=frag->nextfrag;
	} while (1) /* FOR EVER */;
	storeads [0]=nstores;	 
	loadads [0]=nloads;

	/**/
	/* If there are are any registers not defined in the loop and 'dead' on      */
	/* loop entry these can be used. Attempt to use them by looking for          */
	/* register & store ops loading the stoire item and substituting a RR op     */
	/**/
	k=~((firstfrag->rin&255)|((unsigned)firstfrag->rin>>8));
	deadregs=(((~defmask)&255)&k)&usableregs;
	/* until there is a revise wrappers routine we must not use unsaved NONVOLS  */
	/**/
	deadregs&=wrappediregs|(~((1<<EBP)|CALLEESAVEDREGS));
	dumpableregs=usemask|defmask;
	dumpableregs|=(unsigned)dumpableregs>>8;
	dumpableregs=(dumpableregs|(1<<ESP))&255;
	dumpableregs=(dumpableregs^255)&(~deadregs);	/* If dead dont need to dump it */
	/**/
	/* if there are any refs off ESP we can not push to save registers           */
	/**/
	if ((usemask&(257<<ESP))!=0)  dumpableregs=0;
	if ((deadregs|dumpableregs)!=0) {
		if (optimtrace!=0 && peepreport!=0) {
			printf("PHOLE: Loop with unused regs ");
			if (postvalid!=0)  printf(" & accesible postamble");
			phex((int)firstfrag);	 
			p5printregisters(deadregs,0,0);
			printf("\n");
			if (dumpableregs!=0) {
				printf("PHOLE: Loop with spillableregs ");
				p5printregisters(dumpableregs,0,0);	 
				printf("\n");
			}
		}
	}
	deadregs|=dumpableregs*postvalid;	/* Increase regs if we can spill them safely */
	if (deadregs!=0) {
		xtrareg=0;
		while ((((1<<xtrareg)&deadregs))==0)  xtrareg++;
		mostloaded(&loadads[0] ,&storeads[0] ,&lmask,&smask,postvalid,defmask);
		if (lmask!=0) {
			if (((1<<xtrareg)&dumpableregs)!=0) {
				makepush(&preinstrs [preptr],xtrareg);
				makepop(&postinstrs [postptr],xtrareg);
				preptr++;	 
				postptr++;
			}
			arrangeloads(&loadads[0] ,&storeads[0] ,lmask,smask,xtrareg,&preinstrs[0] ,&postinstrs[0] ,&preptr
			    ,&postptr);
			moved=1;	 
			goto repeep;
		}
		frag=firstfrag;
		do {
			curi=(int)BMachineInstr(frag->firstinstr,NEXTCHAIN);
			while (curi!=0) {
				curinstr=(struct instrfmt*)(curi);
				nexti=(int)BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
				nextinstr=(struct instrfmt*)(nexti);
				op=curinstr->opcode;
				if (((INTOPS<=curinstr->group)&&(curinstr->group<=INTOPSu))&&((curinstr->props&LOADINSTR)!=0)&&(curinstr
				    ->datasize==4)&&(curinstr->variant==OPRRM)&&((curinstr->privprops&SIBREQD)==0)&&(unsafeoverlaps(curinstr
				    ,nstores,&storeads[0] )==MONO)) {
					if (((curinstr->privprops&FIXEDINSTR)==0)&&(((1<<curinstr->rs1)&defmask)!=0)) {
						curi=nexti;  
						continue ;
					}
					newinstr=BInsertInstr(frag,curinstr);
					newinstr->opcode=LW;
					newinstr->group=INTLOAD;
					newinstr->rd=xtrareg;
					newinstr->rs1=curinstr->rs1;
					newinstr->props=LOADINSTR|DESTROYABLE;
					newinstr->rdef=257<<xtrareg;
					newinstr->rref=curinstr->rref&(~(257<<curinstr->rd));
					newinstr->privprops=curinstr->privprops|DEADREGUTIL;
					newinstr->disp=curinstr->disp;
					newinstr->datasize=4;
					newinstr->area=curinstr->area;
					newinstr->domain=curinstr->domain;
					newinstr->u0.offset=curinstr->u0.offset;
					newinstr->rmbyte=curinstr->rmbyte;
					newinstr->variant=curinstr->variant;
					newinstr->csize=(curinstr->csize-ARCH(opcodesize(curinstr->opcode,curinstr->variant)))+
					    ARCH(opcodesize(LW
					    ,OPRRM));
					curinstr->variant=OPRR;
					curinstr->rs1=xtrareg;
					curinstr->rref=(1<<curinstr->rd)|(1<<xtrareg);
					curinstr->props=curinstr->props&(~LOADINSTR);
					curinstr->privprops=curinstr->privprops&(~FIXEDINSTR);
					curinstr->area=-1;
					curinstr->domain=0;
					curinstr->csize=1+ARCH(opcodesize(curinstr->opcode,OPRR));
					curinstr->rmbyte=0xC0;
					frag->rdef=frag->rdef|(257<<xtrareg);
					frag->ruse=frag->ruse|(1<<xtrareg);
					if (((1<<xtrareg)&dumpableregs)!=0) {
						makepush(&preinstrs [preptr],xtrareg);
						makepop(&postinstrs [postptr],xtrareg);
						preptr++;	 
						postptr++;
						moved=1;	 
						goto repeep;
					}
					goto again;
				}
				curi=nexti;
			}
			if ((int)frag==(int)lastfrag)   break ;
			frag=frag->nextfrag;
		} while (1) /* FOR EVER */;
	}
	/**/
	/* any register defined only once and which is not used before defn          */
	/* and is valid (loop invariant) can be moved. If there are no stores        */
	/* in the loop any register defined once only in terms of regs               */
	/* not defined in the loop can be moved (mainly loads from frame or GLA)     */
	/**/
	singledef=0;
	for (i=0; i<=7; i++) {
		if (defs [i]==1)  singledef|=1<<i;
	}
	singledef&=~usebeforedef;
	storeseen&=~(((1<<CNST)|(1<<SST))|(1<<PLT));	/* pointers can not touch these areas*/

#if(Language==FORTRAN) 
	storeseen&=~(1<<PARAMS);
#endif;
	/**/
	/* work out which regs are live on exit (including side exit if any)         */
	/**/
	liveexitr=0;
	if (exitlabx!=0)  liveexitr=sideexitfrag->rin;
	if ((lastfrag->props&FALLSTHROUGH)!=0) {
		liveexitr|=postfrag->rin;
	}
	liveexitr=(liveexitr&255)|((unsigned)liveexitr>>8);
	if (optimtrace!=0 && peepreport!=0) {
		printf("\n");
		printf("PHOLE: Loop optimised ");	 
		phex((int)firstfrag);	 
		printf(" ");	 
		phex(singledef);
		printf(" ");	 
		phex(usebeforedef);	 
		printf(" ");	 
		phex(usemask);	 
		printf(" ");	 
		phex(defmask);
		printf(" ");	 
		phex(validdef);	 
		printf(" ");	 
		phex(storeseen);	 
		phex(liveexitr);	 
		printf("\n");
		for (i=0; i<=7; i++)  printf("%3d",defs [i]);
		printf("\n");
	}
	if (singledef==0)  goto repeep;

	moved=0;	 
	condpath=0;
	frag=firstfrag;
	do {
		curi=(int)BMachineInstr(frag->firstinstr,NEXTCHAIN);
		while (curi!=0) {
			curinstr=(struct instrfmt*)(curi);
			nexti=(int)BMachineInstr(curinstr->nextinstr,NEXTCHAIN);
			nextinstr=(struct instrfmt*)(nexti);
			op=curinstr->opcode;
			if ((condpath!=0)&&((curinstr->rdef&(liveexitr|firstfrag->rin))!=0)) {
				curi=nexti;  
				continue ;
			}	/* Care needed in condpath re regvars*/
			if (optimtrace!=0 && peepreport!=0) {
				printf("\n");
				printf("LOOP:Testing");	 
				phex(curi);	 
				printf(" ");	 
				phex(curinstr->cdef);	 
				printf(" ");
				phex(curinstr->rdef);
			}
			if (((curinstr->cdef&(1<<FCCBIT))==0)&&((((curinstr->cref&(1<<FSTP))|curinstr->fref))==0)&&((curinstr
			    ->rdef&255)==(1<<curinstr->rd))&&(((curinstr->rdef&255)&singledef)==(curinstr->rdef&255))) {
				if (curinstr->area==-1)  bit=-1; 
				else if (curinstr->area>30)  bit=0x80000000; 
				else bit=1<<curinstr
				->area;

				if ((curinstr->props&LOADINSTR)!=0) {
					validaccess=0;
					if (((storeseen&bit)==0)||(unsafeoverlaps(curinstr,nstores,&storeads[0] )==MONO)) {
						validaccess=1;
					}
				} else {
					validaccess=1;
				}
				if (optimtrace!=0 && peepreport!=0) {
					if (validaccess!=0)  printf("V"); 
					else printf("NV");
					printf("\n");
				}
				if ((validaccess!=0)&&((((curinstr->rdef&validdef)==curinstr->rdef)&&(curinstr->rdef!=0))&&((curinstr
				    ->rref&defmask)==0))) {
					if (optimtrace!=0 && peepreport!=0) {
						printf("LOOP: Loop HOIST  ");	 
						p5printinstr((struct instrfmt *)curi);	 
						printf("\n");
					}
					curinstr->issueprops=curinstr->issueprops|TPHOISTED;
					BCopyInstr(curinstr,&preinstrs [preptr]);
					BDeleteInstr((struct instrfmt*)curi,0);
					preptr++;
					moved++;
				}
			}
			curi=nexti;
		}
		if ((int)frag==(int)lastfrag)   break ;
		if (frag->labref!=0)  condpath=1;
		frag=frag->nextfrag;
		if (frag->labindex!=0)  condpath=0;	/* end of conditional path */
	} while (1) /* FOR EVER */;

	/**/
	/* now re peephole any blocks which have had instructions moved into them    */
	/**/
repeep:

	if (moved>0) {
		if (preptr>0) {
			/**/
			/* if prevfrag end with a jump a new frag must be obtained and linked in     */
			/* otherwise the delat slot filling is wrecked                               */
			/**/
			if (prevfrag->labref!=0) {
				frag=BObtainFrag();
				frag->prevfrag=prevfrag;
				frag->nextfrag=firstfrag;
				frag->final=firstfrag;	/* In case frag stays empty */
				prevfrag->nextfrag=frag;
				firstfrag->prevfrag=frag;
				prevfrag=frag;
			}
			makepreamble(prevfrag,preptr,&preinstrs[0] );
		}
		if (postptr>0) {
			if (exitlabx!=0)  makepostamble(sideexitfrag,postptr,&postinstrs[0] );
			if (((lastfrag->props&FALLSTHROUGH)!=0)&&((exitlabx==0)||((int)postfrag!=(int)sideexitfrag)))  makepostamble
			(postfrag,postptr,&postinstrs[0] );
		}
		reintegrateregmasks(PI->procfrag);
		BReconvergeLiveness();
		RemoveLoads(prevfrag);
		Cleanupfrag(prevfrag,0);
		frag=firstfrag;
		do {
			RemoveLoads(frag);
			Cleanupfrag(frag,0);
			Doubledefs(frag);
			if ((int)frag==(int)lastfrag)   break ;
			frag=frag->nextfrag;
		} while (1) /* FOR EVER */;
		/**/
		/* if anything has moved out it is possible that some operations that        */
		/* appeared to depend on loop variables no longer do so. Notlikely           */
		/* but worth another shot                                                    */
		/**/
		if (optimtrace!=0 && peepreport!=0) {
			BPrintFrags("Before making a further attempt at loop");
		}
		goto again;
	}
	/**/
	/* can we do any fp instr hoisting                                           */
	/**/
	curinstr=(struct instrfmt*)(fpops [1]);
	/*      printstring("Fop checks"); write(firstfrag_fin,2); write(nfpops,2)   */
	/*      write(postvalid,2); write(curinstr_opcode,2); newline                */
	if ((firstfrag->fin!=0)||(nfpops<2)||(postvalid==0)||(nfpops>maxstores)||((fdefmask&(1<<8))!=0))  return;	/*Fstk full*/
	if (((curinstr->rref&defmask)==0)&&((curinstr->opcode==FLDZ)||(curinstr->opcode==FLD1)||((curinstr->group
	    ==FPLOAD)&&(unsafeoverlaps(curinstr,nstores,&storeads[0] )==MONO)))) {
		for (k=2; k<=nfpops; k++) {
			nextinstr=(struct instrfmt*)(fpops [k]);
			if (!((nextinstr->fdef==0)&&((nextinstr->cdef&(1<<FSTP))==0)))   break ;
		}
		op=nextinstr->opcode;
		if (((FISTP<=op)&&(op<=FSTPm))||(op==FCOMPm)||(op==FCOMPd)) {
			if (optimtrace!=0 && peepreport!=0) {
				printf("LOOP: Loop FHOIST  ");	 
				p5printinstr(curinstr);	 
				printf("\n");
			}
			curinstr->issueprops=curinstr->issueprops|TPHOISTED;
			BCopyInstr(curinstr,&preinstrs [preptr]);
			BDeleteInstr(curinstr,0);
			preptr++;
			moved++;
			if ((FISTP<=op)&&(op<=FSTPm)) {
				nextinstr->opcode=op+3;
			} else {
				if (op==FCOMPm)  nextinstr->opcode=FCOMm; 
				else nextinstr->opcode=FCOMd;

			}
			nextinstr->cdef=nextinstr->cdef&(~(1<<FSTP));
			goto fpeep;
		}
	}
	return;
fpeep:

	for (k=k+1; k<=nfpops; k++) {
		nextinstr=(struct instrfmt*)(fpops [k]);
		nextinstr->rd=nextinstr->rd-1;
		if (nextinstr->variant==FOPPLUSR)  nextinstr->rs1=nextinstr->rs1-1;
		nextinstr->fdef=(unsigned)nextinstr->fdef>>1;
		nextinstr->fref=(unsigned)nextinstr->fref>>1;
		if ((nextinstr->group==FPLOAD)&&(p5memoryoverlap(curinstr,nextinstr,0)==MOEXACT)) {
			nextinstr->opcode=FLDd;
			nextinstr->rs1=14;	/* To give FLD %st(0) if only held value present */
			nextinstr->variant=FOPPLUSR;
			nextinstr->fref=0x8000;
			nextinstr->props=nextinstr->props&(~LOADINSTR);
			nextinstr->csize=2;
			nextinstr->area=-1;
		}
	}
	makefpop(&postinstrs [postptr]);
	postptr++;
	goto repeep;

#undef MAXHOISTS
}

static void looptest(struct fragfmt *frag) {
	/*************************************************************************/
	/** Is this frag the start of a single entry loop ?                     **/
	/*************************************************************************/
	int rtlab,cplab;
	struct fragfmt *lfrag;
	if (!((frag->labindex>0)&&(frag->uses==2)&&((frag->props&FALLENINTO)!=0)&&(frag->switchtab==0)))  return;
	rtlab=frag->labindex;
	if (frag->labref==rtlab) {
		loopopt(frag,frag,0); 
		return;
	}
	lfrag=frag;
	cplab=0;
	while ((int)lfrag!=0) {
		if ((lfrag->labindex>0)&&(lfrag->labindex!=rtlab)) {
			if (!((lfrag->labindex==cplab)&&((lfrag->uses==1)||((lfrag->uses==2)&&((lfrag->props&FALLENINTO)!=0)
			    ))))  return;
			cplab=0;
		}
		if (lfrag->labref==rtlab) {
			loopopt(frag,lfrag,cplab); 
			return;
		}
		if (lfrag->labref!=0) {
			if (cplab!=0)  return;
			cplab=lfrag->labref;
		}
		lfrag=lfrag->nextfrag;
	}
}

/***/
static void integratecontexts(struct fragfmt *procfrag) {
	/*************************************************************************/
	/**    Add info from set contexts into instructions                     **/
	/*************************************************************************/
	struct fragfmt *frag,*nextfrag;
	struct instrfmt *instr,*nextinstr;
	int noalias,unroll;

	noalias=0;	 
	unroll=0;
	nextfrag=procfrag;
	while (nextfrag!=NULL) {
		frag=nextfrag;
		nextfrag=frag->nextfrag;
		nextinstr=frag->firstinstr;
		while (nextinstr!=NULL) {
			instr=nextinstr;
			nextinstr=instr->nextinstr;
			if (instr->group==CXTCHANGE) {
				if ((instr->u0.CXTset&CXTnoalias)!=0)  noalias=NOINTERFERENCE;
				if ((instr->u1.CXTunset&CXTnoalias)!=0)  noalias=0;
				if ((instr->u0.CXTset&CXToverlap)!=0)  unroll=ADJACENTLOOPS;
				if ((instr->u1.CXTunset&CXToverlap)!=0)  unroll=0;
			} else {
				instr->privprops|=noalias|unroll;
			}
		}
	}
}	/* integrate contexts */
/***/
void COptimiseProc() {
	/*******************************************************************************/
	/** perform instruction scheduling and peephole optimisation within procedure **/
	/*******************************************************************************/
	struct fragfmt *frag,*destfrag;
	struct instrfmt *newinstr;
	struct lrecfmt *lrec;
	struct Swtabfmt *swtab;
	int nextfrag,foundcode,traceproc,tabval,i;

	hazardreport=globreport;
	if ((bbschedule|gschedule|leafopt|peepopt)==0)  return;

	/* check that the procedure actually contains some real code */
	foundcode=0;
	nextfrag=(int)PI->procfrag;
	while ((foundcode==0)&&(nextfrag!=0)) {
		frag=(struct fragfmt*)nextfrag;
		if ((int)BMachineInstr(frag->firstinstr,NEXTCHAIN)!=0)  foundcode=1;
		nextfrag=(int)frag->nextfrag;
	}
	if (foundcode==0)  return;
	integratecontexts(PI->procfrag);

	/* determine if tracing should be generated or not */
	traceproc=BGetTraceProc();
	if ((traceproc==0)||(traceproc==ProcNum)) {
		peepreport=globreport;
	} else {
		peepreport=0;
	}
	hazardreport=peepreport;

	/* find any dense switch tables and go through them and mark the */
	/* possible destination fragments with a switch note             */
	nextfrag=(int)PI->procfrag;
	while (nextfrag!=0) {
		frag=(struct fragfmt*)nextfrag;
		if (((frag->props&DSWITCHJUMPFRAG)!=0)&&(frag->nextfrag!=0)) {
			if (frag->switchtab!=0) {
				swtab=(struct Swtabfmt*)(frag->switchtab);
				for (i=0; i<=swtab->Entries-1; i++) {
					tabval=swtab->u0.R [i];
					if (tabval!=-1) {
						if (tabval<0)  tabval=-tabval;
						lrec=BLabRecAd(tabval&0xFFFFFFF);
						destfrag=lrec->frag;
						destfrag->props=destfrag->props|DSWITCHCASEFRAG;
						newinstr=BInsertInstr(destfrag,destfrag->firstinstr);
						newinstr->group=DSWITCHNOTE;
						newinstr->u1.immval=(int)frag;
					}
				}
			}
		}
		nextfrag=(int)frag->nextfrag;
	}

	/* do fragment reorganisation */
	BReorganiseFragments();

	/* peephole optimise the procedure */
	if ((diagnostics==0)&&(peepopt!=0)) 	/* RemoveLoads & stores can remove diags markers */{
		nextfrag=(int)PI->procfrag;
		while (nextfrag!=0) {
			frag=(struct fragfmt*)nextfrag;
			nextfrag=(int)frag->nextfrag;
			RemoveLoads(frag);
		}
		if ((optimtrace!=0)&&(peepreport!=0)&&(miscreport!=0)) {
			BPrintFrags("PHOLE: FRAGMENTS AFTER LOAD REMOVAL");
		}
		nextfrag=(int)PI->procfrag;
		while (nextfrag!=0) {
			frag=(struct fragfmt*)nextfrag;
			nextfrag=(int)frag->nextfrag;
			CombineLitOps(frag);
			DelRedunCompares(frag);
			if (((frag->props&RETURNFRAG)!=0)||((frag->props&(RETURNBRANCH|FALLSTHROUGH))==RETURNBRANCH))  RemoveDeadStores
			(frag);
			if (((frag->props&FALLSTHROUGH)!=0)&&(frag->labrefinstr!=0))  improvecompares(frag);
			if ((PI->privprops&NONVIRTUALFP)==0)  improvereclaims(frag);
			ImproveCondEstablish(frag);
			Cleanupfrag(frag,0);
		}
		if ((optimtrace!=0)&&(peepreport!=0)&&(miscreport!=0)) {
			BPrintFrags("PHOLE: FRAGMENTS AFTER CLEANUP");
		}
		nextfrag=(int)PI->procfrag;
		while (nextfrag!=0) {
			frag=(struct fragfmt*)nextfrag;
			nextfrag=(int)frag->nextfrag;
			Doubledefs(frag);
			looptest(frag);
		}
		if ((optimtrace!=0)&&(peepreport!=0)&&(miscreport!=0)) {
			BPrintFrags("PHOLE: FRAGMENTS AFTER DOUBLE-DEF AND LOOP-OPT");
		}
		nextfrag=(int)PI->procfrag;
		while (nextfrag!=0) {
			frag=(struct fragfmt*)nextfrag;
			nextfrag=(int)frag->nextfrag;
			Cleanupfrag(frag,1);
			Doubledefs(frag);
		}
		if (((Language==FORTRAN)&&(LanguageVariant!=FORTRAN90))||(Language==CCOMP)||((PI->procprops&PP_NOINTERNAL)!=0)
		    ) {
			if ((StackSTflags [0]&4)==0)  RecheckStackStores(PI->procfrag);
			/* can only recheck if no pointers and no inner blks                         */
		}
	}
	if (wrappertype==0)  improveprocentry();
	if ((wrappertype==1)&&((PI->privprops&FRAMEADDRTAKEN)==0))  improveleafentry();

	/* now do the basic block or global scheduling of the procedure - this */
	/* is not possible if the procedure has side entries                   */
#if BUILDWITHGS!=0
	if (gschedule!=0 && (PI->procprops&PP_HASSIDEE)==0) {

		/* do the global scheduling on the procedure */
		int oldsavesize=PI->saveareasize;
		BGlobalSchProc(ProcNum,PI->labadjust,UnkCntrlFlow);

		/* global scheduling may change the register save area size on  */
		/* the stack frame - in which case frame accessing instructions */
		/* have to be modified appropriately                            */
		if (((PI->privprops&(NESTEDCALLS|NONVIRTUALFP))==0)&&(PI->saveareasize!=oldsavesize)) {
			if (optimtrace!=0 && peepreport!=0) {
				printf("PHOLE: READJUSTING STACK FRAME ACCESSES BY ");
				printf("%1d",PI->saveareasize-oldsavesize);
				printf("  OLDSAVESIZE:");
				printf("%1d",oldsavesize);
				printf(" NEWSAVESIZE:");
				printf("%1d",PI->saveareasize);
				printf("\n");
			}
			ReadjustStackAccesses(PI->saveareasize-oldsavesize);
		}

		/* recreate the register liveness after global scheduling -   */
		/* this involves recreating the psuedo instructions for dense */
		/* switches                                                   */
		nextfrag=(int)PI->procfrag;
		while (nextfrag!=0) {
			frag=(struct fragfmt*)nextfrag;
			if (((frag->props&DSWITCHJUMPFRAG)!=0)&&(frag->nextfrag!=0)) {
				if (frag->switchtab!=0) {
					swtab=(struct Swtabfmt*)(frag->switchtab);
					for (i=0; i<=swtab->Entries-1; i++) {
						tabval=swtab->u0.R [i];
						if (tabval!=-1) {
							if (tabval<0)  tabval=-tabval;
							lrec=BLabRecAd(tabval&0xFFFFFFF);
							destfrag=lrec->frag;
							destfrag->props=destfrag->props|DSWITCHCASEFRAG;
							newinstr=BInsertInstr(destfrag,destfrag->firstinstr);
							newinstr->group=DSWITCHNOTE;
							newinstr->u1.immval=(int)frag;
						}
					}
				}
			}
			nextfrag=(int)frag->nextfrag;
		}
		BReconvergeLiveness();

	} else 
#endif
	{
		if (bbschedule!=0)  BBasicBlockSchProc(0);
	}


	/* do final titivation of code */
	FinalTidy(PI->procfrag);

	/* print the final state of the fragments if required */
	if (optimtrace!=0 && peepreport!=0) {
		BPrintFrags("PHOLE: FRAGMENTS AFTER FINAL TITIVATION");
	}
	peepreport=globreport;

}	/*COptimiseProc*/
/***/
/***/
/********************************************************************************/
/**                                                                            **/
/**                        BPROCS INTERFACE FUNCTIONS                          **/
/**                                                                            **/
/********************************************************************************/
/***/
int p5malloc(int size) {
	/**************************************************************************/
	/** This is EPC's interface to the system malloc                         **/
	/**************************************************************************/
	int addr;

#if (OutputASSEMBLER==Positive)
	addr=(int)malloc(size);
#else
	addr=getspace(size);
#endif
	if (addr==0) {
		if ((((bbschedule|gschedule)|leafopt)|peepopt)!=0) {
			Mabort(50);
		} else {
			Mabort(39);
		}
	}
	return addr;
}	/*p5 Malloc*/
/***/
void p5free(void * addr) {
	/**************************************************************************/
	/** This is EPC's interface to the system free                           **/
	/**************************************************************************/
#if (OutputASSEMBLER==Positive)
	free((char *)addr);
#else
	freespace((int)addr);
#endif
}	/*p5 Free*/
/***/
static void outregtext(int reg,struct instrfmt *instr) {
	/*************************************************************************/
	/** OUTPUTS THE REGISTER MNEMONIC FOR REG. There are 3 forms            **/
	/** depending on context so the whole instr record is passed in         **/
	/** to enable special cases to be detected                              **/
	/*************************************************************************/
	if (((instr->privprops&BYTEREGOP)!=0)||((instr->opcode==SB)&&(reg==instr->rd))) {
		printf("%s",bregtext [reg]);
		return;
	}
	if (((instr->opcode==LH)||(instr->opcode==LHU))&&(reg==instr->rd)) {
		printf("%s",regtext [reg]);
		return;
	}
	if ((instr->u2.prefixes [osprefix]==102)||(instr->datasize==2)) {
		printf("%s",wregtext [reg]);
		return;
	}
	printf("%s",regtext [reg]);
}	/* outregtext*/
/***/
/***/
static void printprops(struct instrfmt *instr,int diagassem,int ca) {
	struct lrecfmt *lrec;
	struct fragfmt *addrfrag;
	int iprops,prcomma,x;

	iprops=(instr->issueprops&(~TPGLOBSCHED))&0xFFFF;
	prcomma=0;
	if ((miscreport==0)&&(BIsAnnotated()==0))  return;
	if ((ca>0)&&((instr->props&(CONDITIONALBRANCH|PREDICTED))==(CONDITIONALBRANCH|PREDICTED))) {
		lrec=BLabRecAd(instr->u1.immval);
		addrfrag=lrec->frag;
		x=0;
		if (lrec->frag!=NULL)  x=addrfrag->address-ca;	/* rel jump displcmnt*/
		if ((x>0 && (instr->props&PREDICTEDTAKEN)) ||
		    (x<0 && (instr->props&PREDICTEDTAKEN)!=0))
			  printf("%s[predicion honoured]",commentmark);
		if ((x<0 && !(instr->props&PREDICTEDTAKEN)) ||
		    (x>0 && (instr->props&PREDICTEDTAKEN)))
			 printf("%s[predicion dishonoured]",commentmark);
	}
	if (iprops!=0 || instr->bubbles==255 ||
	    ((instr->props&(DELAYSLOTEXISTS|DELAYSLOTINSTR)) && diagassem) || 
	    (instr->domain!=0 && diagassem!=0)) {
		printf("\t%s[",commentmark);
		if (diagassem!=0 && instr->domain!=0) {
			if (instr->domain>0) {
				printf("DOM %d",instr->domain);
			} else {
				printf("ATD %d",-instr->domain);
			}
			prcomma=1;
		}
		if ((iprops&TPIGSTART)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("IGS");	 
			prcomma=1;
		}
		if ((iprops&TPQUEUED)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("QUEUED");	 
			prcomma=1;
		}
		if ((iprops&TPIFTHEN)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("IT");	 
			prcomma=1;
		}
		if ((iprops&TPIFTHENELSE)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("ITE");	 
			prcomma=1;
		}
		if ((iprops&TPITECOLLAPSE)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("ITE_COLLAPSE");
		}
		if ((iprops&TPLOOPBRANCH)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("LOOP");
		}
		if ((iprops&TPMIGRATED)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("MIGRATED");	 
			prcomma=1;
		}
		if ((iprops&TPCONTSPEC)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("SPECULATIVE");	 
			prcomma=1;
		}
		if ((iprops&TPGLUED)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("GLUED");	 
			prcomma=1;
		}
		if ((iprops&TPCASCADED)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("CASCADED");	 
			prcomma=1;
		}
		if ((iprops&TPCOPYBYPASS)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("COPY_BYPASS");	 
			prcomma=1;
		}
		if ((iprops&TPEARLY)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("EARLY");	 
			prcomma=1;
		}
		if ((iprops&TPHOISTED)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("HOISTED");	 
			prcomma=1;
		}
		if ((iprops&TPREFRESH)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("REFRESH");	 
			prcomma=1;
		}
		if ((iprops&TPOPTACCESS)!=0) {
			if (prcomma!=0)  printf(", ");
			printf("OPT_ACCESS");	 
			prcomma=1;
		}
		if (instr->bubbles==255) {
			if (prcomma!=0)  printf(", ");
			printf("POST_FILL");
		}
		printf("]");
	} else {
		printf("\t%s",commentmark);
	}
	if (instr->rref|instr->fref|instr->cref) {
		printf(" REF:");
		p5printregisters(instr->rref,instr->fref,instr->cref);
	}
	if (instr->rdef|instr->fdef|instr->cdef) {
		printf(" DEF:");
		p5printregisters(instr->rdef	/*&255*/,instr->fdef,instr->cdef);
	}
	printf(" P/PP:%X/%X A/O/S%2d/%2d/%2d",instr->props,
		instr->privprops,instr->area,instr->u0.offset,instr->datasize);	 
	printf(" csize=%d",instr->csize);
}	/*printprops*/
/***/
static void outfixedlit(struct instrfmt *instr) {
	int offset;
	printf("$%s",egivename(instr->area));
	offset=instr->u0.offset-AreaBaseOffset;
	if (offset>0)  printf("+");
	if (offset!=0)  printf("%1d",offset);
}	/* outfixedlit      */
/***/
static void address(struct instrfmt *instr) {
	int Base,Index,scale,offset;
	if ((instr->privprops&SIBREQD)!=0) {
		scale=(unsigned)instr->sib>>6;
		Base=instr->rs1;
		Index=instr->rs2;
	}
	if ((instr->privprops&FIXEDINSTR)==0) {
		if (instr->disp!=0)  printf(itos(instr->disp));
		if ((instr->privprops&SIBREQD)==0) {
			printf("(%s)",regtext [instr->rs1]);
		}
	} else {
		printf(egivename(instr->area));
		offset=instr->u0.offset-AreaBaseOffset;
		if (instr->fixtype==GOTofffix)  printf("@GOT"); 
		else {
			if (instr->fixtype==GOTfix)  printf("@GOTOFF");
			if (offset>0)  printf("+%d",offset);
			if (offset<0)  printf("%1d",offset);
		}
		if (((instr->fixtype==GOTfix)||(instr->fixtype==GOTofffix))&&((instr->privprops&SIBREQD)==0))  printf("(%%ebx)");
	}
	if ((instr->privprops&SIBREQD)!=0) {
		printf("(");
		if ((instr->privprops&FIXEDINSTR)==0 || instr->fixtype==GOTfix)  printf("%s",regtext [Base]);
		printf(",%s,%d)",regtext [Index],1<<scale);
	}
	/***/
}	/* address    */
/***/
void p5disasinstr(struct instrfmt *instr,int *ca) {
	/*********************************************************************/
	/** list the given instruction                                      **/
	/**    ca is the current code address                               **/
	/**    ca = -1 indicates that compiler tracing is being printed     **/
	/**    ca = -2 indicates that compiler tracing is being printed     **/
	/**            bit pipeline bubble information should be suppressed **/
	/**    ca = -3 indicates that compiler tracing is being printed     **/
	/**            and pipeline bubble and some prefixed spacing should **/
	/**            be suppressed                                        **/
	/*********************************************************************/
	struct lrecfmt *lrec;
	struct Exdatafmt *exdata;
	int group,I,J,DiagAssem,form,op,bubbles,jj;
	unsigned char hcode [31+1];
	char mnem [32] ;
	char S [256] ;
	/***/

	/* print GIS pipeline bubble information */
	DiagAssem=0;
	if (*ca<0)  DiagAssem=1;
	if ((instr->bubbles!=0)&&(instr->bubbles!=255)&&(*ca!=-2)&&(*ca!=-3)&&(instr->group<MINPSEUDOGROUP)
	    ) {
		bubbles=instr->bubbles-1;
		if (bubbles!=0) {
			if (DiagAssem==0)  printf(commentmark);
			printf("%c",HT);
			if (OutputASSEMBLER==Positive && instr->group<MINPSEUDOGROUP) {
				printf("%c",HT);
			} else if ((OutputASSEMBLER==Negative)&&(asmlist==0)&&(DiagAssem==0)) {
				printf("%c%c",HT,HT);
			}

			printf("-- ");
			if (bubbles==1) {
				printf("bubble --");
			} else {
				printf("%1d bubbles --",bubbles);
			}
			printf("\n");
			if (*ca<0)  printf("%c",HT);
		}
	}

	group=instr->group;
	op=instr->opcode;
	if ((OutputASSEMBLER==Positive)&&(*ca>=0)) {
		if (group<MINPSEUDOGROUP) {
			printf("%c",HT);
		}
	} else if (*ca<0) {
		*ca=0;
		I=Cgenerateinstr(0,instr,*ca,&hcode[0] );
		printf("%08X  ",(unsigned)instr);
	} else {
		I=Cgenerateinstr(0,instr,*ca,&hcode[0] );
		if ((asmlist==0)&&(I!=0)) {
			puthex(*ca,8);
			printf("  ");
			for (J=1; J<=15; J++) {
				if (J<=(int)hcode [0])  puthex(hcode [J],2);
				else printf("  ");
			}
			if ((int)hcode [0]!=instr->csize)  printf("!***!");
		}
	};

	/***/
	form=instrform [op];
	strcpy(mnem,instrmnem [op]);
	/***/
	/***/
	if ((instr->u2.prefixes [osprefix]==102)&&(imp_resolve(mnem,mnem,"l ",S)==0)) {
		strcat(mnem,"w "); strcat(mnem,S);
	}
	J=instr->u2.prefixes [iprefix];
	if (J==242) {
		printf("repnz \n%c",HT);
	}
	if (J==243) {
		printf("rep \n%c",HT);
	}
	if (group>=31)  switch (group) {

	case MARKER:
		if (DiagAssem!=0) printf("%cMARKER\n",HT);	/*will usually have been processed by now*/
		return;

	case LINENUMBER:
		printf("%s line ",commentmark);
		CPrintLine(instr->u1.immval,instr->u0.offset);
		printf("\n");
		return;

	case REGIONINFO:
		printf(commentmark);
		if (OutputASSEMBLER==Negative&&DiagAssem==0&&asmlist==0) printf("%c%c%c",HT,HT,HT);
		if ((instr->issueprops&RPUNROLLED)!=0) {
			printf("UNROLLED REGION");
		} else {
			printf("REGION");
		}
		printf("%1d",instr->u1.immval);
		if ((instr->issueprops&RPINCELLAR)!=0) printf(" CELLAR");
		if ((instr->issueprops&RPTOPLEVEL)!=0) {
			printf(" [PROCEDURE");
			printf("%1d",ProcNum);
			printf("]");
		}
		if ((instr->issueprops&RPSTART)!=0) {
			printf(" START ");
		} else {
			printf(" END ");
		}
		if ((instr->issueprops&RPCONTAINER)!=0) {
			printf("(CONTAINER)");
		} else if ((instr->issueprops&RPGISRESTRICTED)!=0) {
			printf("(GIS RESTRICTED)");
		} else if ((instr->issueprops&RPBBSCHEDULED)!=0) {
			printf("(BASIC BLOCK SCHEDULED)");
		} else {
			printf("(GLOBALLY SCHEDULED)");
		}

		printf("\n");
		return;

	case LINEDEBUG:			/* line number map        */
#if(OutputASSEMBLER==Positive) 

#if(!((Language==CCOMP)&&(LanguageVariant==USLC)&&(TargetABI==LynxOS))) 
		printf("%c.section%c.text\n",HT,HT);
		printf(".LN%s:",itos(instr->u1.immval));
		printf("\n%c.section",HT);
		printf("%c.line,\"\",@progbits\n",HT);
		printf("%c.align 1\n%c",HT,HT);
		printf(".4byte %s;",itos(instr->u1.immval));
		printf(" .2byte 0xffff; .4byte .LN%s-..text.b",itos(instr->u1.immval));
		printf("\n%c.previous\n",HT);

#endif;

#endif;
		return;

	case DBXINFO:
		if (DiagAssem!=0) printf("%cDBXINFO %1d  0x%X\n",HT,instr->opcode,instr->u1.immval);
#if (OutputASSEMBLER==Positive)
		if (DiagAssem==0) {
			if (instr->opcode==0)  (*(int  *)(instr->u1.immval))=*ca;        /*type 0 = give ca*/
		}
#endif
		return;

	case DSWITCHNOTE:
		if (DiagAssem!=0) printf("%cDSWITCHNOTE 0x%X\n",HT,instr->u1.immval);
		return;

	case DELETED:
		if (DiagAssem!=0) printf("%cDELETED\n",HT);
		return;

	case CXTCHANGE:
		if (DiagAssem!=0) printf("%cCXTCHANGE 0x%x/0x%x\n",HT,instr->u0.CXTset,instr->u1.CXTunset);
		return;

	case FIXUPPOINT:
		if (DiagAssem!=0) printf("%cFIXUPPOINT%3d/%3d\n",HT,instr->area,instr->u0.offset);
		return;

	case COPYASM:
		printf("%c%c%s\n",HT,HT,(char *)instr->u1.immval);
		printf("\n");
		return;
		/***/
	default:
		BADSWITCH(group,__LINE__,__FILE__);
	}	/*end of switch on control operation    */
	if (ca!=NULL) *ca+=instr->csize;
	switch (form) {
		/***/
	case NOFORM:
Oponly:
		printf("%c%s",HT,mnem);
		for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
		if (op==ENTER) {
			printf("%3d,%3d",(unsigned)instr->u1.immval>>8,instr->u1.immval&255);
		}
		if (op==RETN) {
			printf("$");
			puthex(instr->u1.immval,0);
		}
		if (op==FSTSW)  printf("%%ax");	/* GNU AS fussy */
		printprops(instr,DiagAssem,*ca);
		printf("\n");
		return;

	case JFORM:
		printf("%c%s",HT,mnem);
		for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
		if ((instr->props&ANYCALL)==0) {
			if ((instr->opcode==CALL)&&((instr->privprops&KNOWNOFFSET)!=0)) {
				printf(".+%1d",instr->u1.immval+5);
			} else {
				lrec=BLabRecAd(instr->u1.immval);
				printf(".L%s",itos(lrec->labnum));
				printprops(instr,DiagAssem,*ca);
			}
			printf("\n");
			return;
		}

		if ((instr->privprops&DIRECTCALL)!=0) {
			exdata=exrecad(instr->u1.immval);
			if ((OutputASSEMBLER==Negative)&&(exdata->Ca>0))  phex(exdata->Ca);
			else if (strcmp(exdata->Name,"")
			    ==0) {
				printf("<Forward Ref>");
			} else {
				strcpy(S,exdata->Name);
				if (S[1]=='#') S[1]='_';
				if (Pic!=0 && exdata->Ca<=0 && (exdata->flags&4)==0)
				  strcat(S,"@PLT");
				printf(S);
			}

		} else {
			lrec=BLabRecAd(instr->u1.immval);
			printf(".L%s",itos(lrec->labnum));
		}
		printprops(instr,DiagAssem,*ca);
		printf("\n");
		return;

	}	/* end of case based on instr_from */

	/***/
	switch (instr->variant) {
	case OPONLY:
	case FOPONLY:
		goto Oponly;

	case OPPLUSR:
	case OPR:
		printf("%c%s",HT,mnem);
		for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
		if (group==SHIFTS)  printf("%%cl,");
		if ((instr->opcode==CALLPTR)||(instr->opcode==JMPPTR))  printf("*");
		outregtext(instr->rd,instr);
		printprops(instr,DiagAssem,*ca);
		printf("\n");
		return;

	case OPRR:
		printf("%c%s",HT,mnem);
		for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
		if (op==LB) printf("%s",bregtext[instr->rs1]);
		else if (op==MOVSX)  printf("%s",wregtext [instr->rs1]);
		else outregtext(instr->rs1,instr);
		printf(",");
		outregtext(instr->rd,instr);
		printprops(instr,DiagAssem,*ca);
		printf("\n");
		return;

	case OPRLIT:
	case OPRSLIT:
	case OPEAXLIT:
	case OPPLUSRLIT:
		printf("%c%s",HT,mnem);
		for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
		if ((instr->privprops&FIXEDLIT)!=0) {
			outfixedlit(instr);
		} else {
			printf("$");
			if (instr->u1.immval<0 && instr->u1.immval >=-128) {
				printf("%d",instr->u1.immval);	/* assembler treats hex as unsigned */
								/* so instruction is bigger than reqd*/

			} else {
				puthex(instr->u1.immval,0);
			}
		}
		printf(",");
		if (op==IMUL) {
			outregtext(instr->rs1,instr);
			printf(",");
		}
		outregtext(instr->rd,instr);
		printprops(instr,DiagAssem,*ca);
		printf("\n");
		return;

	case OPALLIT:
	case OPBRMLIT:
		if (imp_resolve(mnem,mnem,"l ",S)==0) {
			strcat(mnem,"b "); strcat(mnem,S);
		}
		printf("%c%s",HT,mnem);
		for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
		if ((instr->privprops&FIXEDLIT)!=0) {
			outfixedlit(instr);
		} else {
			printf("$0x%X",instr->u1.immval);
		}
		printf(",%s",bregtext [instr->rd]);
		printprops(instr,DiagAssem,*ca);
		printf("\n");
		return;

	case OPRRM:
		if ((instr->privprops&DSWITCHLOADINSTR)!=0) {
			printf("\n.Sbase%d:\n\t\t%s",instr->u0.offset,mnem);
			for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
			printf(".SW%d-.",instr->u0.offset);
			J=((instr->disp-7)&(-4))+1;
			if (J<0)  printf("%2d",J);
			if (J>0)  printf("+%d",J);
			printf("(%s,%s,4),",regtext [instr->rs1],regtext [instr->rs2]);
		} else {
			printf("\t%s",mnem);
			for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
			address(instr);
			printf(",");
		}
		outregtext(instr->rd,instr);
		printprops(instr,DiagAssem,*ca);
		printf("\n");
		return;

	case OPRMR:
		printf("\t%s",mnem);
		for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
		outregtext(instr->rd,instr);
		printf(",");
		address(instr);
		printprops(instr,DiagAssem,*ca);
		printf("\n");
		return;

	case OPMEM:
	case FOPRM:
		if ((instr->privprops&DSWITCHLOADINSTR)!=0) {
			printf("\n.Sbase%s:\n%c",itos(instr->u0.offset),HT);
			printf("\t%s",mnem);
			for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
			printf("*.SW%d",instr->u0.offset);
			J=instr->disp;
			if (J!=0)  printf("+%d",J);
			printf("(,%s,4)",regtext [instr->rs2]);
		} else {
			printf("\t%s",mnem);
			for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
			address(instr);
		}
		printprops(instr,DiagAssem,*ca);
		printf("\n");
		return;

	case OPBMEMLIT:
		if (imp_resolve(mnem,mnem,"l ",S)==0) {
			strcat(mnem,"b "); strcat(mnem,S);
		}
		printf("\t%s",mnem);
		for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
		printf("$%1d,",instr->u1.immval);
		address(instr);
		printprops(instr,DiagAssem,*ca);
		printf("\n");
		return;

	case OPMEMLIT:
		printf("\t%s",mnem);
		for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
		if ((instr->privprops&FIXEDLIT)!=0) {
			outfixedlit(instr);
		} else {
			printf("$");
			if (instr->datasize==2)  printf("%1d",instr->u1.immval);
			else puthex(instr->u1.immval,0);
		}
		if (op!=PUSH) {
			printf(",");
			address(instr);
		}
		printprops(instr,DiagAssem,*ca);
		printf("\n");
		return;

	case FOPPLUSR:
		if ((imp_resolve(mnem,mnem,"l ",S)==0)||(imp_resolve(mnem,mnem,"s ",S)==0)) {
			strcat(mnem," "); strcat(mnem,S);
		}
		printf("\t%s",mnem);
		for (jj=1; jj<=12-(int)strlen(mnem); jj++) printf(" ");
		if (instr->opcode==FCOMPP) {
			if ((instr->rs1-instr->rd)!=1)  Mabort(975);
		} else if ((instr->opcode==FXCH)||(instr->opcode==FLDd)||(instr->opcode==FSTPd)) {
			printf("%%st(%c)",(instr->rs1-instr->rd)+'0');
		} else if ((FCMOVB<=instr->opcode) && (instr->opcode<=FUCOMIP)) {
			printf("%%st(%c),%%st",(instr->rs1-instr->rd)+'0');
		} else {
			printf("%%st,%%st(%c)",(instr->rs1-instr->rd)+'0');
		}

		printprops(instr,DiagAssem,*ca);
		printf("\n");
		return;
	}			/*end of switch based on instr_variant */


}	/*p5 DisasInstr*/
/***/
void p5printinstr(struct instrfmt * instr) {
	/******************************************************************/
	/** Prints the given instruction with its associated information **/
	/******************************************************************/
	int ca;

	ca=-2;
	printf("%08X    ",(unsigned)instr);
	p5disasinstr(instr,&ca);
	if (instr->group<MINPSEUDOGROUP) {
		printf("P/N:%08X",(unsigned)BMachineInstr(instr->previnstr,PREVCHAIN));
		printf("/%08X",(unsigned)BMachineInstr(instr->nextinstr,NEXTCHAIN));
		if (((instr->rref|instr->fref)|instr->cref)!=0) {
			printf(" REF:");
			p5printregisters(instr->rref,instr->fref,instr->cref);
		}
		if (((instr->rdef|instr->fdef)|instr->cdef)!=0) {
			printf(" DEF:");
			p5printregisters(instr->rdef	/*&255*/,instr->fdef,instr->cdef);
		}
		printf(" P/PP:%X/%X",instr->props,instr->privprops);
		if (instr->area!=-1) {
			printf(" A/O/S:%d/%d/%d",instr->area,instr->u0.offset,instr->datasize);
		}
		if (instr->domain!=0) {
			printf(" DOM:%d",instr->domain);
		}
		printf(" csize=%d\n",instr->csize);
	} else if (instr->group==LINENUMBER) {
		printf("#line %2d\n",instr->u1.immval);
	} else if (instr->group==DELETED) {
		printf("DELETED\n");
	}


}	/*p5 PrintInstr*/
/***/
int p5memoryoverlap(struct instrfmt *instr1,struct instrfmt *instr2,int constbase) {
	/*****************************************************************************/
	/** 'instr1' and 'instr2' are two memory referencing instructions.          **/
	/** Return MO NO     if the memory references definitely do not overla      **/
	/** Return MO YES    if the memory references definitely do overlap         **/
	/** Return MO MAYBE  otherwise.                                             **/
	/** Err on the side of MAYBE.                                               **/
	/** if constbase is non-zero then any base registers are constant between   **/
	/**   the two accesses                                                      **/
	/*****************************************************************************/
	int start1,start2,end1,end2;

	/* see if aliasing can be determined from the domain information */
	/*      printstring("p5memoverlap"); phex(addr(instr1)); space               */
	/*      phex(addr(instr2)); newline                                          */
	/*      write(instr1_area,2); write(instr1_offset,2); write(instr1_domain,2) */
	/*      spaces(10)                                                           */
	/*      write(instr2_area,2); write(instr2_offset,2); write(instr2_domain,2) */
	/*      newline                                                              */

	if (instr1->domain!=0 || instr2->domain!=0) {
		if ((instr1->domain!=0)&&(instr2->domain!=0)) {
			if (instr1->domain!=instr2->domain)  return MONO;
		} else if (instr1->domain<0) {
			return MONO;
		} else if (instr2->domain<0) {
			return MONO;
		}


	}

	/* see if aliasing can be determined from the area information */
	if (instr1->area!=instr2->area) {

		/* differing ordinary areas indicate that the accesses can't overlap */
		if (instr1->area>=0 && instr2->area>=0)  return MONO;

		/* Nothing can overlap stack unless frame address has been taken */
		if ((PI->privprops&FRAMEADDRTAKEN)==0 && 
			(instr1->area==STACK || instr2->area==STACK))  return MONO;
		/* Nothing can overlap PARAMS unless param address has been taken */
		if ((paramSTflags [0]&4)==0 && 
			(instr1->area==PARAMS || instr2->area==PARAMS))  return MONO;

		/* FORTRAN scalars are in GLA and arrays are in GST so these    */
		/* can not overlap                                              */

#if(Language==FORTRAN) 
		if (instr1->area==GLA && (instr2->privprops&SIBREQD)!=0)  return MONO;
		if (instr2->area==GLA && (instr1->privprops&SIBREQD)!=0)  return MONO;

#endif;
	} else if (instr1->area>=0) {

		/* the areas are the same so we may be able to use offsets to */
		/* determine if the accesses are aliased                      */

		start1=instr1->u0.offset;
		start2=instr2->u0.offset;
		if (instr1->fixtype!=instr2->fixtype)  return MOMAYBE;
		if (start1!=-1 && start2!=-1 && ((instr1->privprops|instr2->privprops)&SIBREQD)==0) {
			end1=start1+instr1->datasize-1;
			end2=start2+instr2->datasize-1;
			if (start1==start2 && end1==end2)  return MOEXACT;
			if ((start2<=start1 && start1<=end2) || (start1<=start2 && start2<=end1))  return MOYES;
			return MONO;
		}

	};


	/**/
	/* A push or pop that does not have a memory operand can only clash with     */
	/* a store reference via ESP and then only when ESP is not being used for    */
	/* Frame access in a leaf routine. (NB only pushed in a leaf routime are     */
	/* those to save and restore ESI,EDI,EBX                                     */
	/**/

	if (instr1->variant!=OPMEM && 
		(instr1->opcode==POP || instr1->opcode==PUSH) &&
		((instr2->rref&(1<<ESP))==0 || (instr2->privprops&FRAMEACCESS)!=0))  return MONO;

	if (instr2->variant!=OPMEM &&
		(instr2->opcode==POP || instr2->opcode==PUSH) &&
		((instr1->rref&(1<<ESP))==0 || (instr1->privprops&FRAMEACCESS)!=0))  return MONO;

	if ((((instr1->privprops|instr2->privprops)&(SYMBOLICACCESS|FIXEDINSTR)))!=0)  return MOMAYBE;	/* base register invalid for symbolic access */

     if (instr1->group==STROP || instr2->group==STROP) return MOMAYBE;

	if (instr1->rs1==instr2->rs1 && (constbase!=0 || instr1->rs1==FRAMEPOINTER) && 
		((((instr1->privprops|instr2->privprops)&SIBREQD)==0) ||
		(constbase!=0 && (instr1->privprops&instr2->privprops&SIBREQD)!=0 &&
		instr1->sib==instr2->sib && instr1->rs2==instr2->rs2))) {

		/* base reg plus constant offset */
		start1=instr1->disp;
		start2=instr2->disp;
		end1=(start1+instr1->datasize)-1;
		end2=(start2+instr2->datasize)-1;

		if ((start1==start2)&&(end1==end2))  return MOEXACT;
		if (((start2<=start1)&&(start1<=end2))||((start1<=start2)&&(start2<=end1)))  return MOYES;
		return MONO;

	} else {

		/* base regs not the same: we do not know if the accesses overlap */
		return MOMAYBE;

	}

}	/*p5 MemoryOverlap*/
/***/
int p5hasannullableslots() {
	/*************************************************************************/
	/** Returns a non-zero value if annullable delay slots are available.   **/
	/** This is always false on 486 and Pentium.                            **/
	/*************************************************************************/
	return 0;
}	/*p5 HasAnnullableSlots*/
/***/
void p5filldelayslot(struct fragfmt *frag,struct instrfmt *instr) {
	/*****************************************************************************/
	/** If the delay slot is empty for a call or jump attempt to fill it from   **/
	/** the previous instruction stream                                         **/
	/** No delayslots on pentium but bprocs reference must be satisfied     **/
	/*****************************************************************************/
}	/*p5 FillDelaySlot*/
/***/
void p5printarchinfo(int archinfo) {
	/*******************************************************************************/
	/** Prints architecture specific information which is associated with a       **/
	/** fragment.                                                                 **/
	/*******************************************************************************/
	if (archinfo!=0) {
		printf("ARCHINFO: ");
		puthex(archinfo,0);
		printf("\n");
	}
}	/*p5 PrintArchInfo*/
/***/
void p5deleteswitch(struct fragfmt *frag) {
	/**************************************************************************/
	/** Given that the contents of a dense switch jump fragment has been     **/
	/** deleted, goes ahead and deletes any associated switch table. On      **/
	/** p5 the switch table is always associated with the same fragment.   **/
	/**************************************************************************/
	if (frag->switchtab==0) {
		p5Error("p5 DeleteSwitch: Switch table not found");
	}
	frag->switchtab=0;
}	/*p5 DeleteSwitch*/
/***/
int p5improveswitch(struct fragfmt *frag) {
	/**************************************************************************/
	/** For switch tables check each destination to see whether it is itself **/
	/** an unconditional branch -- if so, change the table entry to point    **/
	/** directly to destination's destination; apply repeatedly. Returns a   **/
	/** non-zero value if any change to the table was made.                  **/
	/**************************************************************************/
	struct fragfmt *destfrag,*notefrag;
	struct instrfmt *destinstr,*oldnote,*nexti;
	struct lrecfmt *lrec;
	struct Swtabfmt *swtab;
	int j,prevchanges,changes,tabval;

	changes=0;
	swtab=(struct Swtabfmt*)(frag->switchtab);
	if (swtab->Mode!=SPARSESWITCH) {

		/* check that the fragment is marked correctly */
		if ((frag->props&DSWITCHJUMPFRAG)==0) 
			p5Error("p5 ImproveSwitch: Cannot find jump fragment");

		do {
			if (changes>SENSIBLEITER)
				p5Error("p5 ImproveSwitch: Too many iterations");
			prevchanges=changes;
			for (j=0; j<=swtab->Entries-1; j++) {
				tabval=swtab->u0.R [j];
				if (tabval!=-1) {
					if (tabval<0)  tabval=-tabval;
					lrec=BLabRecAd(tabval&0xFFFFFFF);
					tabval=lrec->labnum;
				}
				if (tabval!=-1) {
					notefrag=lrec->frag;
					destfrag=notefrag->final;
					destinstr=BMachineInstr(destfrag->firstinstr,NEXTCHAIN);
					if (destinstr==NULL)   continue ;
					if ((destinstr->props&BRANCH)==0 || 
					   (destinstr->props&CONDITIONALBRANCH)!=0 ||
					   destinstr->opcode!=JMP ||
					   ((destinstr->props&DELAYSLOTEXISTS)!=0 &&
						(destinstr->props&DELAYSLOTUNUSED)==0)) {
						continue ;
					}
					lrec=BLabRecAd(destinstr->u1.immval);
					swtab->u0.R [j]=BLocateLabel(lrec->labnum,0);

					/* locate the existing dense switch note */
					nexti=notefrag->firstinstr;
					while (nexti!=NULL) {
						oldnote=nexti;
						if (oldnote->group==DSWITCHNOTE &&
						   oldnote->u1.immval==(int)frag)  break;
						nexti=oldnote->nextinstr;
					}
					if (nexti==NULL)
						p5Error("p5 ImproveSwitch: Switch note missing");

					/* update the fragment use counts and properties */
					destfrag->uses--;
					destfrag=lrec->frag;
					destfrag->props|=DSWITCHCASEFRAG;
					destfrag=destfrag->final;
					destfrag->uses++;

					/* move the dense switch note to the new destination frag */
					destfrag=lrec->frag;
					BMoveBefore(notefrag,destfrag,oldnote,destfrag->firstinstr);

					changes++;
					if (optimtrace!=0 && peepreport!=0)
						printf("PHOLE: FRAGMENT: %08X  IMPROVED DENSE SWITCH TO %08X\n",
							(unsigned)frag,(unsigned)notefrag);
				}
			}
		} while (changes!=prevchanges) ;
	}
	return changes;
}	/*p5 ImproveSwitch*/
/***/
int p5improvereturn(struct fragfmt *frag) {
	/**************************************************************************/
	/** Modifies unconditional branches to returns into direct return        **/
	/** instructions. This optimisation is not performed on MIPS.            **/
	/**************************************************************************/
	return 0;
}	/*p5 ImproveReturn*/
/***/
void p5printswitch(struct fragfmt *frag) {
	/**************************************************************************/
	/** Prints the labels used in a dense switch table                       **/
	/**************************************************************************/
	struct Swtabfmt *swtab;
	struct lrecfmt *lrec;
	int tabval,i;

	swtab=(struct Swtabfmt*)(frag->switchtab);
	if (swtab->Mode!=SPARSESWITCH) {
		printf("SWITCH TABLE LABELS:");
		for (i=0; i<=swtab->Entries-1; i++) {
			tabval=swtab->u0.R [i];
			if (tabval!=-1) {
				if (tabval<0)  tabval=-tabval;
				lrec=BLabRecAd(tabval&0xFFFFFFF);
				printf(" .L%d",lrec->labnum);
			}
		}
		printf("\n");
	}

}	/*p5 PrintSwitch*/
/***/
void p5printregisters(int gvector,int fvector,int cvector) {
	/*******************************************************************************/
	/** Prints the set of registers represented by the given bit vectors          **/
	/*******************************************************************************/
	int reg;

	if ((gvector==-1)&&(fvector==-1)&&(cvector==-1)) {
		printf("ALL");
	} else {
		reg=0;
		while (reg<16) {
			if ((gvector&(1<<reg))!=0) {
				printf("%s",regtext [reg&7]);
				if (reg>=8)  printf("-Beta "); 
				else printf(" ");
				reg++;
			} else {
				reg++;
			}
		}
		reg=0;
		while (reg<8) {
			if ((fvector&(1<<reg))!=0) {
				printf("%s",regtext [reg+8]);
				printf(" ");
				reg++;
			} else {
				reg++;
			}
		}
		for (reg=0; reg<=Maxcreg; reg++) {
			if (cvector&(1<<reg))  printf(" %s",Qregtext [reg]);
		}
	}
}	/*p5 PrintRegisters*/
/***/
void p5printentryname(int entryid) {
	/*******************************************************************************/
	/** Prints the name of the procedure or entry point with the given identifier **/
	/*******************************************************************************/
	struct Exdatafmt *exdata;

	exdata=exrecad(entryid);
	printf("PROCEDURE: ");
	printf(exdata->Name);
}	/*p5 PrintEntryName*/
/***/
int p5createuncond(int labindex) {
	/********************************************************************************/
	/** Creates an unconditional jump instruction which is not linked in any       **/
	/** instruction chain. The branch is to the given label index. The             **/
	/** DELAY SLOT UNUSED property for the instruction is set to indicate that it  **/
	/** requires a delay slot instruction.                                         **/
	/********************************************************************************/
	struct instrfmt *instr;

	instr=BObtainInstr();
	instr->group=instrgroup [JMP];
	instr->opcode=JMP;
	instr->rs1=0;
	instr->rs2=0;
	instr->u1.immval=labindex;
	instr->props=(((instr->props|BRANCH)|DELAYSLOTUNUSED)|DELAYSLOTEXISTS)|DSMUSTEXIST;
	return (int)instr;
}	/*p5 CreateUncond*/
/***/
int p5askforlabelnum() {
	/********************************************************************************/
	/** Returns a new unique label number that is not currently used in the code   **/
	/********************************************************************************/
	return Mprivatelabel()+PI->labadjust;
}	/*p5 AskForLabelNum*/
/***/
void p5flushoutput(int selstdout) {
	/********************************************************************************/
	/** Flushes any output streams - this allows C and IMP output to be mixed for  **/
	/** languages in which the IMP library routines are not implemented in C. If   **/
	/** selstdout is non-zero then the standard output stream is selected for IMP. **/
	/********************************************************************************/


#if((Language!=CCOMP)||(LanguageVariant!=USLC)) 
#endif;
}	/*p5 FlushOutput*/
/***/
void p5setlabelrefs(struct fragfmt *frag) {
	/*******************************************************************************/
	/** Updates fragment use counts for any label references (other than          **/
	/** branches) made in the given fragment. If these references are no taken    **/
	/** into account then the label might look dead to the fragment reorganiser   **/
	/** and will thus be deleted. On p5 the possible destination fragments of   **/
	/** a dense switch have to handled by this routine.                           **/
	/*******************************************************************************/
	struct fragfmt *destfrag;
	struct Swtabfmt *swtab;
	struct lrecfmt *lrec;
	int tabval,i;

	if (frag->switchtab!=0) {
		swtab=(struct Swtabfmt*)(frag->switchtab);
		if (swtab->Mode!=SPARSESWITCH) {
			for (i=0; i<=swtab->Entries-1; i++) {
				tabval=swtab->u0.R [i];
				if (tabval!=-1) {
					if (tabval<0)  tabval=-tabval;
					lrec=BLabRecAd(tabval&0xFFFFFFF);
					destfrag=lrec->frag;
					destfrag=destfrag->final;
					destfrag->uses=destfrag->uses+1;
				}
			}
		}
	}
}	/*p5 SetLabelRefs*/
/***/
int p5conditionmatch(struct instrfmt *instr1,struct instrfmt *instr2) {
	/*****************************************************************************/
	/** 'instraddr1' is the address of a jump instruction.                      **/
	/** If 'instraddr2 is the address of another jump instruction whose 'true'  **/
	/** condition includes that of the first jump, then return 1 else return 0  **/
	/**                                                                         **/
	/** The return value will be used to decide whether to replace the first    **/
	/** jump's destination with the second's destination if appropriate - thus  **/
	/** other checks may be applicable in this routine.                         **/
	/*****************************************************************************/
	int op1,op2,cond1,cond2,ca;

	if (instr2==NULL)  return 0;	/* don't think this can happen */


	op1=instr1->opcode;	 
	cond1=(instr1->rs1<<8)|instr1->rs2;
	op2=instr2->opcode;	 
	cond2=(instr2->rs1<<8)|instr2->rs2;

	if ((instr1->group!=BCC)||(instr2->group!=BCC))  return 0;

	/*      %RESULT = 0 %IF cond1 = NEVER %OR cond2 = NEVER                      */
	/*a jump never happens*/

	if ((instr2->props&(BRANCH|CONDITIONALBRANCH))==BRANCH)  goto match;
	/*the condition of the 2nd jump is a superset of the 1st*/

	/* test for inclusive conditions */
	if (((cond1==cond2)&&(op1==op2)))  goto match;	/* identical operations */
	return 0;
match:

	if (optimtrace!=0 && peepreport!=0) {
		printf("PHOLE: Condition match :%08X %08X\n",(unsigned)instr1,(unsigned)instr2);	 
		ca=-1;
		p5disasinstr(instr1,&ca);	 
		p5disasinstr(instr2,&ca);
	}
	return 1;
}	/*p5 ConditionMatch*/
/***/
int p5isaddrlabel(int label) {
	/*******************************************************************************/
	/** Returns a non-zero value if the given label has been addressed.           **/
	/*******************************************************************************/
	return Maddressedlabel(label);
}	/*p5 IsAddrLabel*/
/***/
/***/
/********************************************************************************/
/**                                                                            **/
/**               p5 GIS DELTA AND BPROCS SUPPORT FUNCTIONS                  **/
/**                                                                            **/
/********************************************************************************/
/***/
/* to save paper */
int p5invertbranch(struct instrfmt *instr,int predtaken,int istest) {
	/*****************************************************************************/
	/** 'instr' is a conditional jump : invert the condition for which it jumps **/
	/**     eg                                                                  **/
	/**          bge   L123        becomes       blt   L123                     **/
	/**                                                                         **/
	/** 'predtaken' does not apply to p5                                      **/
	/*****************************************************************************/
	if (instr->opcode==JMP) {
		p5Error("p5 InvertBranch: Cannot invert jump");
	}
	if (istest==0)  instr->opcode=InverseJump [instr->opcode-(JO)];
	return 0;	/* no branch prediction */
}	/*p5 InvertBranch*/
/***/
int p5createnop() {
	/********************************************************************************/
	/** Creates a NOP instruction which is not linked in any instruction chain     **/
	/********************************************************************************/
	struct instrfmt *instr;

	instr=BObtainInstr();
	instr->group=instrgroup [NOP];
	instr->opcode=NOP;
	instr->u1.immval=0;
	return (int)instr;
}	/*p5 CreateNOP*/
/***/
/***/
/********************************************************************************/
/**                                                                            **/
/**                     p5 GIS DELTA SUPPORT FUNCTIONS                       **/
/**                                                                            **/
/********************************************************************************/
/***/

#if(BUILDWITHGS>0) 
static unsigned char RetOpRegs [9+1];
static unsigned char RetOpAliases [9+1];
static unsigned char RetOpMasks [9+1];
static unsigned char RetOpProps [9+1];
static int fp0popop(int opcode) {
	/*************************************************************************/
	/** returns 0 unless opcode is a FPOP that does not pop the FSTACK      **/
	/*************************************************************************/
	if (opcode==FIADDm || opcode==FADDm || opcode==FADDd)  return 1;
	if (opcode==FIMULm || opcode==FMULm || opcode==FMULd)  return 1;
	if (opcode==FISUBm || opcode==FSUBm || opcode==FSUBd)  return 1;
	if (opcode==FISUBRm || opcode==FSUBRm || opcode==FSUBRd)  return 1;
	if (opcode==FIDIVm || opcode==FDIVm || opcode==FDIVd)  return 1;
	if (opcode==FIDIVRm || opcode==FDIVRm || opcode==FDIVRd)  return 1;
	if (opcode==FICOMm || opcode==FCOMm || opcode==FCOMd)  return 1;
	if (opcode==FABS || opcode==FCHS || opcode==FTST || opcode==FRNDINT)  return 1;
	return 0;
}	/* of fp0popop*/
/***/
static int fp1popop(int opcode) {
	/*************************************************************************/
	/** returns 0 unless opcode is a FPOP that pops the FSTACK once         **/
	/*************************************************************************/
	if (opcode==FADDP || opcode==FSUBP || opcode==FMULP || opcode==FDIVP ||
		opcode==FSUBRP || opcode==FDIVRP)  return 1;
	if (opcode==FICOMPm || opcode==FCOMPm || opcode==FCOMPd || opcode==FCOMP)  return 1;
	return 0;
}	/* of fp1popop*/
static void ReadjustStackAccesses(int adjustment) {
	/************************************************************************/
	/** Adjusts accesses to the stack frame via the stack pointer after    **/
	/** global scheduling has been performed if the size of the register   **/
	/** save area changes                                                  **/
	/************************************************************************/
	struct fragfmt *curfrag,*frag;
	struct instrfmt *instr,*curinstr;

	/* update any offsets for accesses via the stack pointer */
	curfrag=PI->procfrag;
	while (curfrag!=NULL) 	/*through all frags in this procedure*/{
		frag=curfrag;
		curinstr=frag->firstinstr;
		while (curinstr!=NULL) 	/*through all instructions in this frag*/{
			instr=curinstr;
			if (((instr->privprops&FRAMEACCESS)!=0)&&((instr->rref&(1<<STACKPOINTER))!=0)) {
				if (instr->disp>127)  instr->csize+=-3;
				instr->disp+=adjustment;
				if (instr->disp>127)  instr->csize+=3;	/* In case crossint 127 changes lit size*/
			}
			curinstr=instr->nextinstr;
		}
		curfrag=frag->nextfrag;
	}

	/* modify the prologue stack size */
	frag=PI->procfrag;
	curinstr=(struct instrfmt *)(int)BMachineInstr(frag->firstinstr,NEXTCHAIN);
	while (curinstr!=NULL) {
		instr=curinstr;
		if (((instr->rdef&(1<<STACKPOINTER))!=0)&&((instr->props&FRAMEMODIFY)!=0)) {
			if (instr->opcode==SUB) {
				instr->u1.immval+=adjustment;  
				break ;
			}
			if (instr->opcode==ENTER) {
				instr->u1.immval+=(adjustment<<8);  
				break ;
			}
			p5Error("Illegal frame modify instruction");
		}
		curinstr=(struct instrfmt *)(int)BMachineInstr(instr->nextinstr,NEXTCHAIN);
	}

	/* modify the epilogue stack size */
	curfrag=PI->procfrag;
	while (curfrag!=NULL) {
		frag=curfrag;
		if ((frag->props&RETURNFRAG)!=0) {
			curinstr=(struct instrfmt *)(int)BMachineInstr(frag->lastinstr,PREVCHAIN);
			while (curinstr!=NULL) {
				instr=curinstr;
				if (((instr->rdef&(1<<STACKPOINTER))!=0)&&((instr->props&FRAMEMODIFY)!=0)) {
					if (instr->opcode==ADD) {
						instr->u1.immval+=adjustment;  
						break ;
					}
					p5Error("Illegal frame modify instruction");
				}
				curinstr=(struct instrfmt *)(int)BMachineInstr(instr->previnstr,PREVCHAIN);
			}
		}
		curfrag=frag->nextfrag;
	}

}	/*ReadjustStackAccesses*/
/***/
int p5CanRewriteFixInstr(struct instrfmt *instr,int area,int offset) {
	/********************************************************************************/
	/** Determines if the given instruction can be rewritten to use a fixed up     **/
	/** value with the given area and offset. This is not possible for any         **/
	/** instructions on MIPS.                                                      **/
	/********************************************************************************/
	return 0;
}	/*p5 CanRewriteFixInstr*/
/***/
int p5CreateNewLabel() {
	/********************************************************************************/
	/** Creates a new unique label that is not currently used in the code. The     **/
	/** label definition point must be later set using a B SetEntryLabel call.     **/
	/********************************************************************************/
	struct lrecfmt *lrec;
	int labnum,labindex;

	labnum=Mprivatelabel()+PI->labadjust;
	labindex=BLocateLabel(labnum,0);
	lrec=BLabRecAd(labindex);
	return (int)lrec;
}	/*p5 CreateNewLabel*/
/***/
int p5DuplicateFrag(struct fragfmt *frag) {
	/********************************************************************************/
	/** Generates a duplicate of the given fragment and returns a pointer to the   **/
	/** duplicate which is not linked into any fragment chain.                     **/
	/********************************************************************************/
	struct fragfmt *newfrag;

	newfrag=BObtainFrag();
	BCopyFrag(frag,newfrag);
	newfrag->prevfrag=0;
	newfrag->nextfrag=0;
	newfrag->final=(int)newfrag;
	return (int)newfrag;
}	/*p5 DuplicateFrag*/
/***/
int p5DuplicateInstr(struct instrfmt *instr) {
	/********************************************************************************/
	/** Generates a duplicate of the given instruction and returns a pointer to    **/
	/** the duplicate which is not linked into any instruction chain               **/
	/********************************************************************************/
	struct instrfmt *newinstr;

	newinstr=BObtainInstr();
	BCopyInstr(instr,newinstr);
	newinstr->previnstr=0;
	newinstr->nextinstr=0;
	newinstr->issueprops=0;
	newinstr->bubbles=0;
	return (int)newinstr;
}	/*p5 DuplicateInstr*/
/***/
void p5GenRestoreWrapper(struct fragfmt *exit,int regsa,int regsb,int regsc,int regsd) {
	/********************************************************************************/
	/** Generates code to restore the given callee preserved registers at the end  **/
	/** of the given exit fragment. Wrapper instructions will already exist so     **/
	/** we make use of these were possible, deleting existing ones or inserting    **/
	/** new ones as required.                                                      **/
	/********************************************************************************/
	struct instrfmt *instr,*retinstr;
	int newregsa,newregsb,redunregsa,redunregsb,nexti,reg,offset,previ;
	int movestackset,foundspdef;

	/* if no register expansion was allowed then we don't have to do anything */
	if ((PI->privprops&NOREGEXPAN)!=0)  return;

}	/*p5 GenRestoreWrapper*/
/***/
void p5GenSaveWrapper(struct fragfmt *entry,int regsa,int regsb,int regsc,int regsd) {
	/********************************************************************************/
	/** Generates code to store the given callee preserved registers at the start  **/
	/** of the given entry fragment. Wrapper instructions will already exist so    **/
	/** we make use of these were possible, deleting existing ones or inserting    **/
	/** new ones as required.                                                      **/
	/********************************************************************************/
	struct instrfmt *instr,*tempinstr;
	int newregsa,newregsb,redunregsa,redunregsb,nexti,reg,offset;
	int foundspdef,movestackset,tempi;

	/* if no register expansion was allowed then we don't have to do anything */
	if ((PI->privprops&NOREGEXPAN)!=0)  return;

}	/*p5 GenSaveWrapper*/
/***/
void p5GetAccessInfo(struct instrfmt *instr,int *basereg,int *offset,int *size,int *props) {
	/********************************************************************************/
	/** Obtains information about the given memory access instruction. Basereg is  **/
	/** set to the number of the base register. Offset is set to a byte offset if  **/
	/** the AI LIT OFFSET property is set or is undefined if the AI FIX OFFSET     **/
	/** property is set. Size is set to the width of the access in bytes and props **/
	/** is set to give a properties vector for the access.                         **/
	/********************************************************************************/
	if ((instr->props&(LOADINSTR|STOREINSTR))==0) {
		p5Error("p5 GetAccessInfo: Instruction is not a memory access");
	}
	if ((instr->privprops&VOLATILELOC)!=0) {
		*props=AIVOLATILE;
	} else {
		*props=0;
	}
	*basereg=instr->rs1;
	*size=instr->datasize;
	if ((instr->privprops&(SYMBOLICACCESS|FIXEDINSTR))!=0) {
		*props|=AIFIXOFFSET;
	} else {
		*props|=AILITOFFSET;
		*offset=instr->u1.immval;
	}

#if(Language==FORTRAN) 
	if (instr->area==STACK)  *props|=AIDOMEXCL;

#endif;
}	/*p5 GetAccessInfo*/
/***/
void p5GetFixupInfo(struct instrfmt *instr,int *base,int *offset,int *ispartial,int *isupper) {
	/********************************************************************************/
	/** Obtains fixup information for an instruction which has a fixed up operand. **/
	/** Base is set to the area of the fixup and offset to the byte offset.        **/
	/** Ispartial is set to non-zero if the fixup is only partial and isupper is   **/
	/** set to non-zero if the fixup is to be upper part of the word. This         **/
	/** function should only be applied to instructions which return a positive    **/
	/** response to p5 IsFixupInstr.                                             **/
	/********************************************************************************/
	*base=instr->area;
	*offset=instr->u0.offset;
	if ((instr->privprops&SYMBOLICACCESS)!=0) {
		*ispartial=0;
	} else {
		*ispartial=1;
		*isupper=0;
	}
}	/*p5 GetFixupInfo*/
/***/
int p5GetFragProps(struct fragfmt *frag) {
	/********************************************************************************/
	/** Returns the properties associated with the given fragment in the form of a **/
	/** bit vector                                                                 **/
	/********************************************************************************/
	int props;

	if ((frag->props&FALLSTHROUGH)!=0) {
		props=FPFALLSTHROUGH;
	} else {
		props=0;
	}
	if ((frag->props&FALLENINTO)!=0) {
		props|=FPFALLENINTO;
	}
	if (((frag->props&((USERASSEMFRAG|DSWITCHJUMPFRAG)|NOGISFRAG))!=0)||(frag->switchtab!=0)) {
		props|=FPNOGIS;
	}
	if ((frag->props&RETURNFRAG)!=0) {
		props|=FPRETURNS;
	}
	if ((frag->props&RETURNBRANCH)!=0) {
		props|=FPRETBRANCH;
	}
	return props;
}	/*p5 GetFragProps*/
/***/
int p5GetInstrProps(struct instrfmt *instr) {
	/********************************************************************************/
	/** Obtains a bit vector giving the properties for the given instruction       **/
	/********************************************************************************/
	return instr->props;
}	/*p5 GetInstrProps*/
/***/
int p5GetLitOp(struct instrfmt *instr) {
	/********************************************************************************/
	/** Gets the immediate operand of the given instruction. This function should  **/
	/** only be called for instructions which return a positive response to the    **/
	/** p5 HasLitOp function.                                                    **/
	/********************************************************************************/
	int form;

	form=instrform [instr->opcode];
	return instr->u1.immval;
}	/*p5 GetLitOp*/
/***/
void p5GetOperands(struct instrfmt *instr,int *numops,int *opregs,int *opaliases,int *opmasks,int *opprops
) {
	/********************************************************************************/
	/** Obtains information regarding the operands of the given instruction.       **/
	/** Numops is set to the number of operands which the instruction has. The     **/
	/** opregs, opaliases, opmasks and opprops are set to point to the base of     **/
	/** byte arrays holding information about the operands. These arrays are only  **/
	/** temporary and may be reused by the next call of this function. opregs      **/
	/** gives the registers (or first register in a pair) for each operand or -1   **/
	/** if the operand uses an immediate operand. Opaliases, opmasks and opprops   **/
	/** are defined for each register operand. Register aliases are not used on    **/
	/** the p5 architecture. Opprops gives the properties for each register      **/
	/** operand.                                                                   **/
	/********************************************************************************/
	int a_value;
	int curreg,form,op;

	*opregs=(int)&RetOpRegs [0];
	*opaliases=(int)&RetOpAliases [0];
	*opmasks=(int)&RetOpMasks [0];
	*opprops=(int)&RetOpProps [0];
	form=instrform [instr->opcode];
	goto a_skip;
a_despatch:
	switch (a_value) {
	default:
		BADSWITCH(a_value,__LINE__,__FILE__);
	}
a_skip:
	;
}	/*p5 GetOperands*/
/***/
void p5GetReadRegs(struct instrfmt *instr,int *regsa,int *regsb,int *regsc,int *regsd) {
	/********************************************************************************/
	/** Sets regsa, regsb, regsc and regsd to the set of registers referenced by   **/
	/** the given instruction. Exempt registers referenced by the instruction are  **/
	/** ignored.                                                                   **/
	/********************************************************************************/
	*regsa=instr->rref&0xFFFFFFFE;
	*regsb=instr->fref;
	*regsc=instr->cref;
	*regsd=0;
}	/*p5 GetReadRegs*/
/***/
int p5GetRegDomain(struct fragfmt *frag,int regnum) {
	/********************************************************************************/
	/** Determines if the given register holds an address pointing to a particular **/
	/** domain on exit from the given fragment. The number of the domain is        **/
	/** returned or 0 if there is no domain information for the register. Negative **/
	/** values represent exclusive domains and positive values represent           **/
	/** inclusive domains.                                                         **/
	/********************************************************************************/
	struct instrfmt *instr;
	int previ,searchreg;

	previ=(int)BMachineInstr(frag->lastinstr,PREVCHAIN);
	while (previ!=0) {
		instr=(struct instrfmt*)(previ);
		if ((instr->rdef&(1<<regnum))!=0) {
			if ((instr->rd==regnum)&&(instr->domain!=0)&&((instr->props&DELAYSLOTINSTR)==0)) {
				return instr->domain;
			}
			return 0;
		}
		previ=(int)BMachineInstr(instr->previnstr,PREVCHAIN);
	}
	return 0;
}	/*p5 GetRegDomain*/
/***/
void p5GetRegFixup(struct fragfmt *frag,int regnum,int *base,int *offset,int *ispartial,int *isupper
) {
	/********************************************************************************/
	/** Determines if the given register holds a fixed up address on exit from the **/
	/** given fragment. Base is set to the area of the fixup or -1 if there is no  **/
	/** fixup associated with the register. Offset is set to the displacement      **/
	/** within the area. Ispartial is set to a non-zero value if the fixup is only **/
	/** to part of the register and isupper is set to a non-zero value if it is    **/
	/** the upper part of the register which is fixed up.                          **/
	/********************************************************************************/
	struct instrfmt *instr;
	int previ,searchreg;

}	/*p5 GetRegFixup*/
/***/
void p5GetWrapperInfo(int *regsa,int *regsb,int *regsc,int *regsd) {
	/********************************************************************************/
	/** Obtains wrapper information for the function being globally scheduled.     **/
	/** Regsa - regsd are set to the set of callee preserved registers that may be **/
	/** used by the scheduler.                                                     **/
	/********************************************************************************/
	if ((PI->privprops&NOREGEXPAN)!=0) {
		*regsa=PI->rdef|(~CALLEESAVEDREGS);
		*regsb=PI->fdef|(~CALLEESAVEDFREGS);
	} else {
		*regsa=-1;
		*regsb=-1;
	}
	*regsc=-1;
	*regsd=-1;
}	/*p5 GetWrapperInfo*/
/***/
void p5GetWriteRegs(struct instrfmt *instr,int *regsa,int *regsb,int *regsc,int *regsd,int incwindow
) {
	/********************************************************************************/
	/** Gets the set of registers which are modified by the given instruction.     **/
	/** Exempt registers written by the instruction are ignored. Incwindow is      **/
	/** ignored on MIPS.                                                           **/
	/********************************************************************************/
	*regsa=instr->rdef&0xFFFFFFFE;
	*regsb=instr->fdef;
	*regsc=instr->cdef;
	*regsd=0;
}	/*p5 GetWriteRegs*/
/***/
int p5HasAssociate(struct instrfmt *instr) {
	/********************************************************************************/
	/** Returns a non-zero result if the given instruction has an associate. There **/
	/** are no associate instructions on MIPS.                                     **/
	/********************************************************************************/
	return 0;
}	/*p5 HasAssociate*/
/***/
int p5HasFixedDS(struct instrfmt *instr) {
	/********************************************************************************/
	/** Returns a non-zero value if the given instruction is a delay slot owner    **/
	/** with a fixed delay slot instruction. There are no fixed delay slot         **/
	/** instructions on MIPS.                                                      **/
	/********************************************************************************/
	return 0;
}	/*p5 HasFixedDS*/
/***/
int p5HasLitOp(struct instrfmt *instr) {
	/********************************************************************************/
	/** Returns a non-zero value if the given instruction has an immediate         **/
	/** operand. The operand itself may be obtained with p5 GetLitOp.            **/
	/********************************************************************************/
	int form;

	form=instrform [instr->opcode];
	/*    %IF form # DForm %AND form # DUForm %AND form # SAForm %THEN %RESULT = 0*/
	return 1;
}	/*p5 HasLitOp*/
/***/
int p5IsFixupInstr(struct instrfmt *instr) {
	/********************************************************************************/
	/** Returns a non-zero value if the given instruction has an operand which     **/
	/** is fixed up. Information may be obtained about the fixup using the         **/
	/** p5 GetFixupInfo function.                                                **/
	/********************************************************************************/
	if ((instr->privprops&SYMBOLICACCESS)!=0) {
		return 1;
	} else if ((instr->privprops&FIXEDINSTR)!=0) {
		return 1;
	}

	return 0;
}	/*p5 IsFixupInstr*/
/***/
int p5IsNotSelfAlias(int area) {
	/********************************************************************************/
	/** Returns a non-zero value if the given area cannot be self-aliased. That    **/
	/** is, there will be no pointers in the area which point to other parts of    **/
	/** same area. This is currently hard-wired to the library array '__iob' which **/
	/** holds character I/O information.                                           **/
	/********************************************************************************/
	char S [41] ;


#if(Language==CCOMP) 
	strcpy(S,egivename(area));
	if (strcmp(S,"__iob")==0)  return 1;

#endif;
	return 0;
}	/*p5 IsNotSelfAlias*/
/***/
int p5IsUnlikelyCall(struct instrfmt *instr) {
	/********************************************************************************/
	/** Returns a non-zero value if the given instruction is a call to a function  **/
	/** which is unlikely to be called. This is currently hard-wired to the        **/
	/** library functions '__flsbuf' and '__filbuf'. These are used to flush or    **/
	/** fill, respectively, the character I/O buffers. These are much less likely  **/
	/** to be called than the alternative of putting a character into or removing  **/
	/** a character from the buffer.                                               **/
	/********************************************************************************/
	char S [41] ;

	return 0;
}	/*p5 IsUnlikelyCall*/
/***/
void p5RewriteFixInstr(struct instrfmt *instr,int offset) {
	/********************************************************************************/
	/** Rewrites an instruction which uses a fixup to use another register fixed   **/
	/** up to a potentially different offset in the same area. This is not         **/
	/** possible on the p5 architecture.                                         **/
	/********************************************************************************/
}	/*p5 RewriteFixInstr*/
/***/
void p5SetOperands(struct instrfmt *instr,int numops,int opregs,int issueprops,int bubbles) {
	/********************************************************************************/
	/** Sets the operand registers for the given instruction. The instruction has  **/
	/** numops operands (obtained from a previous p5 GetOperands call). Opregs   **/
	/** is a byte array giving the registers allocated to each operand. Operands   **/
	/** which represent an immediate value or exempt register have a register      **/
	/** allocation of NO NEW REG. Issueprops gives information about the issue of  **/
	/** the instruction from GIS and bubbles gives the estimated number of         **/
	/** pipeline bubbles preceeding the issue of the instruction.                  **/
	/********************************************************************************/
	int a_value;
	int form,op;

	/* check that the instruction has been committed */
	if ((instr->bubbles==0)&&((instr->previnstr!=0)||(instr->nextinstr!=0))) {
		p5Error("p5 SetOperands: Cannot modify uncommitted instruction");
	}

	/* set the GIS timing information for the instruction */
	if (instr->bubbles!=0) {
		if (bubbles>=254)  bubbles=253;
		instr->bubbles=bubbles+1;
	}
	instr->issueprops=instr->issueprops|issueprops;

	/* set the operand information */
	form=instrform [instr->opcode];
	goto a_skip;
a_despatch:
	switch (a_value) {
	default:
		BADSWITCH(a_value,__LINE__,__FILE__);
	}
a_skip:
	;
}	/*p5 SetOperands*/
/***/
int p5TraceReg(int regnum) {
	/********************************************************************************/
	/** Prints the symbolic form of the given register and returns the number of   **/
	/** characters printed                                                         **/
	/********************************************************************************/
	int junk,len;

}	/*p5 TraceReg*/
/***/

#endif;

/* end of automatic translation */

