xref: /csrg-svn/old/as.vax/asjxxx.c (revision 595)
1*595Sbill /* Copyright (c) 1980 Regents of the University of California */
2*595Sbill static	char sccsid[] = "@(#)asjxxx.c 4.1 08/13/80";
3*595Sbill #include	<stdio.h>
4*595Sbill #include	<sys/types.h>
5*595Sbill #include	"as.h"
6*595Sbill #include	"assyms.h"
7*595Sbill 
8*595Sbill #define JBR 0x11
9*595Sbill #define BRW 0x31
10*595Sbill 
11*595Sbill /*
12*595Sbill  *	The number of bytes to add if the jxxx must be "exploded"
13*595Sbill  *	into the long form
14*595Sbill  */
15*595Sbill #define	JBRFSIZE	1	/*goes to brw*/
16*595Sbill #define JXXXFSIZE	3	/*goes to brb, brw <byte> <byte> */
17*595Sbill 
18*595Sbill /*
19*595Sbill  *	These variables are filled by asscan.c with the
20*595Sbill  *	last name encountered (a pointer buried in the intermediate file),
21*595Sbill  *	and the last jxxx symbol table entry encountered.
22*595Sbill  */
23*595Sbill struct 	symtab	*lastnam;
24*595Sbill struct	symtab	*lastjxxx;
25*595Sbill 
26*595Sbill /*
27*595Sbill  *	Handle jxxx instructions
28*595Sbill  */
29*595Sbill ijxout(op,ap,nact)
30*595Sbill 	struct arg *ap;
31*595Sbill {
32*595Sbill 	if (passno == 1){
33*595Sbill 		/*
34*595Sbill 		 *	READ THIS BEFORE LOOKING AT jxxxfix()
35*595Sbill 		 *
36*595Sbill 		 *	Record the jxxx in a special symbol table entry
37*595Sbill 		 */
38*595Sbill 		register struct symtab *jumpfrom;
39*595Sbill 
40*595Sbill 		/*
41*595Sbill 		 *	We assume the MINIMAL length
42*595Sbill 		 */
43*595Sbill 		putins(op,ap,nact);
44*595Sbill 		jumpfrom = lastjxxx;
45*595Sbill 		jumpfrom->tag = JXACTIVE;
46*595Sbill 		jumpfrom->jxbump = 0;
47*595Sbill 		if (op == JBR)
48*595Sbill 			jumpfrom->jxfear = JBRFSIZE;
49*595Sbill 		else
50*595Sbill 			jumpfrom->jxfear = JXXXFSIZE;
51*595Sbill 		if (lastnam == 0)
52*595Sbill 			yyerror("jxxx destination not a label");
53*595Sbill 		jumpfrom->dest = lastnam;
54*595Sbill 		jumpfrom->type = dotp->xtype;	/*only TEXT or DATA*/
55*595Sbill 		jumpfrom->index = dotp-usedot;
56*595Sbill 		/*
57*595Sbill 		 *	value ALWAYS (ALWAYS!!!) indexes the next instruction
58*595Sbill 		 *	after the jump, even in the jump must be exploded
59*595Sbill 		 *	(bumped)
60*595Sbill 		 */
61*595Sbill 		jumpfrom->value = dotp->xvalue;
62*595Sbill 		njxxx++;
63*595Sbill 	} else {/* pass2, resolve */
64*595Sbill 		/*
65*595Sbill 		 *	READ THIS AFTER LOOKING AT jxxxfix()
66*595Sbill 		 */
67*595Sbill 		register long		oxvalue;
68*595Sbill 		register struct	exp 	*xp;
69*595Sbill 		register struct symtab	*tunnel;
70*595Sbill 		register struct arg	*aplast;
71*595Sbill 
72*595Sbill 		aplast = ap + nact - 1;
73*595Sbill 		xp = aplast->xp;
74*595Sbill 		if (lastjxxx->tag == JXTUNNEL){
75*595Sbill 			lastjxxx->tag = JXINACTIVE;
76*595Sbill 			tunnel = lastjxxx->dest;
77*595Sbill 			xp->xvalue = tunnel->value	/*index of instruction following*/
78*595Sbill 				    - 3			/* size of brw + word*/
79*595Sbill 				    + ( ( (tunnel->jxfear == JBRFSIZE) &&
80*595Sbill 					  (tunnel->jxbump == 0))?1:0);
81*595Sbill 							/*non bumped branch byteis only 2 back*/
82*595Sbill 		}
83*595Sbill 		if (lastjxxx->jxbump == 0){	/*wasn't bumped, so is short form*/
84*595Sbill 			putins(op, ap, nact);
85*595Sbill 		} else {
86*595Sbill 			if (op != JBR){	/*branch reverse conditional byte over
87*595Sbill 					  branch unconditional word*/
88*595Sbill 				oxvalue = xp->xvalue;
89*595Sbill 				xp->xvalue = lastjxxx->value;
90*595Sbill 				putins(op^1, ap, nact);
91*595Sbill 				xp->xvalue = oxvalue;
92*595Sbill 			}
93*595Sbill 			putins(BRW, aplast, 1);
94*595Sbill 		}
95*595Sbill 	}
96*595Sbill }	/*end of ijxout*/
97*595Sbill 
98*595Sbill jalign(xp, sp)
99*595Sbill 	register struct exp *xp;
100*595Sbill 	register struct symtab *sp;
101*595Sbill {
102*595Sbill 	register	int	mask;
103*595Sbill 	if (xp->xtype != XABS || xp->xvalue < 0 || xp->xvalue > 16) {
104*595Sbill 		yyerror("Illegal `align' argument");
105*595Sbill 		return;
106*595Sbill 	}
107*595Sbill 	flushfield(NBPW/4);
108*595Sbill 	if (passno == 1) {
109*595Sbill 		sp->tag = JXALIGN;
110*595Sbill 		sp->jxfear = (1 << xp->xvalue) - 1;
111*595Sbill 		sp->type = dotp->xtype;
112*595Sbill 		sp->index = dotp-usedot;
113*595Sbill 		/*
114*595Sbill 		 *	We guess that the align will take up at least one
115*595Sbill 		 *	byte in the code output.  We will correct for this
116*595Sbill 		 *	initial high guess when we explode (bump) aligns
117*595Sbill 		 *	when we fix the jxxxes.  We must do this guess
118*595Sbill 		 *	so that the symbol table is sorted correctly
119*595Sbill 		 *	and labels declared to fall before the align
120*595Sbill 		 *	really get their, instead of guessing zero size
121*595Sbill 		 *	and have the label (incorrectly) fall after the jxxx.
122*595Sbill 		 *	This is a quirk of our requirement that indices into
123*595Sbill 		 *	the code stream point to the next byte following
124*595Sbill 		 *	the logical entry in the symbol table
125*595Sbill 		 */
126*595Sbill 		dotp->xvalue += 1;
127*595Sbill 		sp->value = dotp->xvalue;
128*595Sbill 		njxxx++;
129*595Sbill 	} else {
130*595Sbill 		mask = (1 << xp->xvalue) - 1;
131*595Sbill 		while (dotp->xvalue & mask){
132*595Sbill #ifdef UNIX
133*595Sbill 			outb(0);
134*595Sbill #endif UNIX
135*595Sbill #ifdef VMS
136*595Sbill 			*vms_obj_ptr++ = -1;
137*595Sbill 			*vms_obj_ptr++ = 0;
138*595Sbill 			dotp->xvalue += 1;
139*595Sbill #endif VMS
140*595Sbill 		}
141*595Sbill 	}
142*595Sbill }
143*595Sbill 
144*595Sbill /*
145*595Sbill  *	Pass 1.5, resolve jxxx instructions and .align in .text
146*595Sbill  */
147*595Sbill jxxxfix()
148*595Sbill {
149*595Sbill 	register struct symtab 	*jumpfrom;
150*595Sbill 		 struct symtab	**cojumpfrom, *ubjumpfrom;
151*595Sbill 	register struct symtab 	*dest;
152*595Sbill 	register struct symtab	*intdest;	/*intermediate dest*/
153*595Sbill 	register struct symtab	**cointdest, *ubintdest;
154*595Sbill 
155*595Sbill 	register struct symtab 	*tunnel;
156*595Sbill 	 	 int 		displ,nchange;
157*595Sbill 		 int		badjxalign;	/*if jump across an align*/
158*595Sbill 		 int		stillactives;	/*if still active jxxxes*/
159*595Sbill 		 int		segno;		/*current segment number*/
160*595Sbill 		 int		topono;		/*which iteration in the topo sort*/
161*595Sbill 	register unsigned char	tag;
162*595Sbill 	/*
163*595Sbill 	 *	consider each segment in turn...
164*595Sbill 	 */
165*595Sbill 	for (segno = 0; segno < NLOC + NLOC; segno++){
166*595Sbill 	    badjxalign = 0;		/*done on a per segment basis*/
167*595Sbill 	    /*
168*595Sbill 	     *	Do a lazy topological sort.
169*595Sbill 	     */
170*595Sbill 	    for (topono = 1, nchange = 1; nchange != 0; topono++){
171*595Sbill #ifdef DEBUG
172*595Sbill 		if (debug)
173*595Sbill 			printf("\nSegment %d, topo iteration %d\n",
174*595Sbill 				segno, topono);
175*595Sbill #endif
176*595Sbill 		nchange = 0;
177*595Sbill 		stillactives = 0;
178*595Sbill 		/*
179*595Sbill 		 *	We keep track of one possible tunnel location.
180*595Sbill 		 *	A tunnel will eventually be an unconditional
181*595Sbill 		 *	branch to the same place that another jxxx
182*595Sbill 		 *	will want to branch to.  We will turn a
183*595Sbill 		 *	branch conditional/unconditional (word) that would
184*595Sbill 		 *	have to get bumped because its destination is too
185*595Sbill 		 *	far away, into a branch conditional/unconditional
186*595Sbill 		 *	byte to the tunnel branch conditional/unconditional.
187*595Sbill 		 *	Of course, the tunnel must branch to the same place
188*595Sbill 		 *	as we want to go.
189*595Sbill 		 */
190*595Sbill 		tunnel = 0;	/*initially, no tunnel*/
191*595Sbill 		SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){
192*595Sbill 			tag = jumpfrom->tag;
193*595Sbill 			if (tag <= IGNOREBOUND)
194*595Sbill 				continue;	/*just an ordinary symbol*/
195*595Sbill 			if (tag == JXALIGN){
196*595Sbill 				tunnel = 0;	/*avoid tunneling across a flex alocation*/
197*595Sbill 				continue;	/*we take care of these later*/
198*595Sbill 			}
199*595Sbill 			if (   jumpfrom->jxfear == JBRFSIZE	/*unconditional*/
200*595Sbill 			    || (   tag == JXINACTIVE		/*inactive bumped*/
201*595Sbill 				&& (jumpfrom->jxbump != 0)
202*595Sbill 			       )
203*595Sbill 			   ) tunnel = jumpfrom;
204*595Sbill 			if (tag != JXACTIVE)
205*595Sbill 				continue;
206*595Sbill 			dest = jumpfrom->dest;
207*595Sbill 			if (jumpfrom->index != dest->index){
208*595Sbill 				yyerror("Intersegment jxxx");
209*595Sbill 				continue;
210*595Sbill 			}
211*595Sbill 			displ = dest->value - jumpfrom->value;
212*595Sbill 			if (displ < MINBYTE || displ > MAXBYTE) {
213*595Sbill 				/*
214*595Sbill 				 *	This is an immediate lose!
215*595Sbill 				 *
216*595Sbill 				 *	We first attempt to tunnel
217*595Sbill 				 *	by finding an intervening jump that
218*595Sbill 				 *	has  the same destination.
219*595Sbill 				 *	The tunnel is always the first preceeding
220*595Sbill 				 *	jxxx instruction, so the displacement
221*595Sbill 				 *	to the tunnel is less than zero, and
222*595Sbill 				 *	its relative position will be unaffected
223*595Sbill 				 *	by future jxxx expansions.
224*595Sbill 				 */
225*595Sbill 				if (    (jumpfrom->jxfear > JBRFSIZE)
226*595Sbill 				     && (tunnel)
227*595Sbill 				     && (tunnel->dest == jumpfrom->dest)
228*595Sbill 				     && (tunnel->index == jumpfrom->index)
229*595Sbill 				     && (tunnel->value - jumpfrom->value >=
230*595Sbill 						MINBYTE + JXXXFSIZE)
231*595Sbill 				   ) {
232*595Sbill 						/*
233*595Sbill 						 *	tunnelling is OK
234*595Sbill 						 */
235*595Sbill 						jumpfrom->dest = tunnel;
236*595Sbill 						/*
237*595Sbill 						 * no bumping needed, this
238*595Sbill 						 * is now effectively inactive
239*595Sbill 						 * but must be remembered
240*595Sbill 						 */
241*595Sbill 						jumpfrom->tag = JXTUNNEL;
242*595Sbill #ifdef DEBUG
243*595Sbill 						if(debug)
244*595Sbill 						printf("Tunnel from %s from line %d\n",
245*595Sbill 							jumpfrom->name, lineno);
246*595Sbill #endif
247*595Sbill 						continue;
248*595Sbill 				} else {	/*tunneling not possible*/
249*595Sbill 					/*
250*595Sbill 					 *	since this will be turned
251*595Sbill 					 *	into a bumped jump, we can
252*595Sbill 					 *	use the unconditional jump
253*595Sbill 					 *	as a tunnel
254*595Sbill 					 */
255*595Sbill 					tunnel = jumpfrom;
256*595Sbill 					jumpfrom->tag = JXNOTYET;
257*595Sbill 					++nchange;
258*595Sbill 					continue;
259*595Sbill 				}
260*595Sbill 			}	/*end of immediate lose*/
261*595Sbill 			/*
262*595Sbill 			 *	Do a forward search for an intervening jxxx
263*595Sbill 			 */
264*595Sbill 			if (displ >= 0) {
265*595Sbill 				SEGITERATE(segno, cojumpfrom + 1,0,cointdest,
266*595Sbill 						intdest, ubintdest, ++){
267*595Sbill 					if (intdest->value > dest->value)
268*595Sbill 						break; /* beyond destination */
269*595Sbill 					if (intdest->tag <= JXQUESTIONABLE)
270*595Sbill 						continue;	/*frozen solid*/
271*595Sbill 					if (intdest->tag == JXALIGN){
272*595Sbill 						jumpfrom->jxoveralign = 1;
273*595Sbill 						badjxalign++;
274*595Sbill 					}
275*595Sbill 					/*
276*595Sbill 					 *	we assume the worst case
277*595Sbill 					 *	for unfrozen jxxxxes
278*595Sbill 					 */
279*595Sbill 					displ += intdest->jxfear;
280*595Sbill 				}
281*595Sbill 				if (displ <= MAXBYTE){
282*595Sbill 					/*
283*595Sbill 					 *	the worst possible conditions
284*595Sbill 					 *	can't hurt us, so forget about
285*595Sbill 					 *	this jump
286*595Sbill 					 */
287*595Sbill 					jumpfrom->tag = JXINACTIVE;
288*595Sbill 				} else {
289*595Sbill 					stillactives++;
290*595Sbill 				}
291*595Sbill 			} else {
292*595Sbill 			/*
293*595Sbill 			 *	backward search for intervening jxxx
294*595Sbill 			 */
295*595Sbill 				SEGITERATE(segno, cojumpfrom - 1,1,cointdest,
296*595Sbill 				  intdest, ubintdest, --){
297*595Sbill 					if (intdest->value <= dest->value)
298*595Sbill 						break; /* beyond destination */
299*595Sbill 					if (intdest->tag <= JXQUESTIONABLE)
300*595Sbill 						continue;	/*frozen solid*/
301*595Sbill 					if (intdest->tag == JXALIGN){
302*595Sbill 						jumpfrom->jxoveralign = 1;
303*595Sbill 						badjxalign++;
304*595Sbill 					}
305*595Sbill 					displ -= intdest->jxfear;
306*595Sbill 				}
307*595Sbill 				if (displ >= MINBYTE) {
308*595Sbill 					jumpfrom->tag = JXINACTIVE;
309*595Sbill 				} else {
310*595Sbill 					stillactives++;
311*595Sbill 				}
312*595Sbill 			}	/*end of backwards search*/
313*595Sbill 		}	/*end of iterating through all symbols in this seg*/
314*595Sbill 
315*595Sbill 		if (nchange == 0) {
316*595Sbill 			/*
317*595Sbill 			 *	Now, if there are still active jxxx entries,
318*595Sbill 			 *	we are partially deadlocked.  We can leave
319*595Sbill 			 *	these jxxx entries in their assumed short jump
320*595Sbill 			 *	form, as all initial displacement calcualtions
321*595Sbill 			 *	are hanging on unresolved jxxx instructions
322*595Sbill 			 *	that might explode into a long form, causing
323*595Sbill 			 *	other jxxxes jumping across the first set of
324*595Sbill 			 *	jxxxes to explode, etc.
325*595Sbill 			 *	However, if a jxxx jumps across a .align,
326*595Sbill 			 *	we assume the worst for the deadlock cycle,
327*595Sbill 			 *	and resolve all of them towards the long
328*595Sbill 			 *	jump.
329*595Sbill 			 *	Currently, the C compiler does not produce
330*595Sbill 			 *	jumps across aligns, as aligns are only used
331*595Sbill 			 *	in data segments, or in text segments to align
332*595Sbill 			 *	functions.
333*595Sbill 			 */
334*595Sbill 			if (stillactives){
335*595Sbill 				SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom,
336*595Sbill 				    ubjumpfrom, ++){
337*595Sbill 					if (jumpfrom->tag == JXACTIVE){
338*595Sbill 						jumpfrom->tag =
339*595Sbill 						  badjxalign?JXNOTYET:JXINACTIVE;
340*595Sbill 					}
341*595Sbill 				}
342*595Sbill 				if (badjxalign){
343*595Sbill 					jxxxbump(segno, (struct symtab **)0);
344*595Sbill 				}
345*595Sbill 			}
346*595Sbill 			/*
347*595Sbill 			 *	Handle  all of the .align s
348*595Sbill 			 */
349*595Sbill 			SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom,
350*595Sbill 			   ubjumpfrom, ++){
351*595Sbill 			    if (jumpfrom->tag == JXALIGN){
352*595Sbill 				/*
353*595Sbill 				 *	Predict the true displacement
354*595Sbill 				 *	needed, irregardless of the
355*595Sbill 				 *	fact that we guessed 1
356*595Sbill 				 */
357*595Sbill 				displ = (jumpfrom->value - 1) & (unsigned)jumpfrom->jxfear;
358*595Sbill 				if (displ == 0){	/*no virtual displacement*/
359*595Sbill 					jumpfrom->jxfear = -1;
360*595Sbill 				} else {
361*595Sbill 					jumpfrom->jxfear = (jumpfrom->jxfear + 1) - displ;
362*595Sbill 					/*
363*595Sbill 					 *	assert jumpfrom->jxfear > 0
364*595Sbill 					 */
365*595Sbill 					if (jumpfrom->jxfear == 1){
366*595Sbill 						/*our prediction was correct*/
367*595Sbill 						continue;
368*595Sbill 					}
369*595Sbill 					/*
370*595Sbill 					 *	assert jumpfrom->jxfear > 1
371*595Sbill 					 */
372*595Sbill 					jumpfrom->jxfear -= 1;	/*correct guess*/
373*595Sbill 				}
374*595Sbill 				/*
375*595Sbill 				 *	assert jumpfrom->jxfear = -1, +1...2**n-1
376*595Sbill 				 */
377*595Sbill 				jumpfrom->tag = JXNOTYET;	/*signal*/
378*595Sbill 				jxxxbump(segno, cojumpfrom);
379*595Sbill 				jumpfrom->tag = JXINACTIVE;
380*595Sbill 				/*
381*595Sbill 				 *	Assert jxfrom->jxvalue indexes the first
382*595Sbill 				 *	code byte after the added bytes, and
383*595Sbill 				 *	has n low order zeroes.
384*595Sbill 				 */
385*595Sbill 			  }
386*595Sbill 			}	/*end of walking through each segment*/
387*595Sbill 	    	}	/*end of no changes */
388*595Sbill 		else {	/*changes, and still have to try another pass*/
389*595Sbill 			jxxxbump(segno, (struct symtab **)0);
390*595Sbill 		}
391*595Sbill 	   }	/*end of doing the topologic sort*/
392*595Sbill 	}	/*end of iterating through all segments*/
393*595Sbill }	/*end of jxxxfix*/
394*595Sbill 
395*595Sbill /*
396*595Sbill  *	Go through the symbols in a given segment number,
397*595Sbill  *	and see which entries are jxxx entries that have
398*595Sbill  *	been logically "exploded" (expanded), but for which
399*595Sbill  *	the value of textually following symbols has not been
400*595Sbill  *	increased
401*595Sbill  */
402*595Sbill 
403*595Sbill jxxxbump(segno, starthint)
404*595Sbill 	int	segno;
405*595Sbill 	struct	symtab **starthint;
406*595Sbill {
407*595Sbill 	register	struct	symtab	**cosp, *sp;
408*595Sbill 	register	struct	symtab		*ub;
409*595Sbill 	register	int	cum_bump;
410*595Sbill 	register	unsigned	char	tag;
411*595Sbill 
412*595Sbill 	cum_bump = 0;
413*595Sbill 	SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){
414*595Sbill 		tag = sp->tag;
415*595Sbill 		if (tag == JXNOTYET){
416*595Sbill #ifdef DEBUG
417*595Sbill 			if (debug){
418*595Sbill 			if (sp->dest != 0)
419*595Sbill 				printf("Explode jump to %s on line %d\n",
420*595Sbill 					sp->dest->name, lineno);
421*595Sbill 			else
422*595Sbill 				printf("Explode an align!\n");
423*595Sbill 			}
424*595Sbill #endif
425*595Sbill 			sp->tag = JXINACTIVE;
426*595Sbill 			sp->jxbump = 1;
427*595Sbill 			cum_bump += sp->jxfear;
428*595Sbill 		}
429*595Sbill 		/*
430*595Sbill 		 *	Only bump labels and jxxxes. Ignored entries can
431*595Sbill 		 *	be incremented, as they are thrown away later on.
432*595Sbill 		 *	Stabds are given their final value in the second
433*595Sbill 		 *	pass.
434*595Sbill 		 */
435*595Sbill 		if (tag >= OKTOBUMP)	/*only bump labels and jxxxes and floating stabs*/
436*595Sbill 			sp->value += cum_bump;
437*595Sbill 	}
438*595Sbill 	usedot[segno].xvalue += cum_bump;
439*595Sbill }
440