xref: /csrg-svn/old/as.vax/asjxxx.c (revision 630)
1595Sbill /* Copyright (c) 1980 Regents of the University of California */
2*630Shenry static	char sccsid[] = "@(#)asjxxx.c 4.2 08/15/80";
3595Sbill #include	<stdio.h>
4595Sbill #include	"as.h"
5595Sbill #include	"assyms.h"
6595Sbill 
7595Sbill #define JBR 0x11
8595Sbill #define BRW 0x31
9595Sbill 
10595Sbill /*
11595Sbill  *	The number of bytes to add if the jxxx must be "exploded"
12595Sbill  *	into the long form
13595Sbill  */
14595Sbill #define	JBRFSIZE	1	/*goes to brw*/
15595Sbill #define JXXXFSIZE	3	/*goes to brb, brw <byte> <byte> */
16595Sbill 
17595Sbill /*
18595Sbill  *	These variables are filled by asscan.c with the
19595Sbill  *	last name encountered (a pointer buried in the intermediate file),
20595Sbill  *	and the last jxxx symbol table entry encountered.
21595Sbill  */
22595Sbill struct 	symtab	*lastnam;
23595Sbill struct	symtab	*lastjxxx;
24595Sbill 
25595Sbill /*
26595Sbill  *	Handle jxxx instructions
27595Sbill  */
28595Sbill ijxout(op,ap,nact)
29595Sbill 	struct arg *ap;
30595Sbill {
31595Sbill 	if (passno == 1){
32595Sbill 		/*
33595Sbill 		 *	READ THIS BEFORE LOOKING AT jxxxfix()
34595Sbill 		 *
35595Sbill 		 *	Record the jxxx in a special symbol table entry
36595Sbill 		 */
37595Sbill 		register struct symtab *jumpfrom;
38595Sbill 
39595Sbill 		/*
40595Sbill 		 *	We assume the MINIMAL length
41595Sbill 		 */
42595Sbill 		putins(op,ap,nact);
43595Sbill 		jumpfrom = lastjxxx;
44*630Shenry 		jumpfrom->s_tag = JXACTIVE;
45*630Shenry 		jumpfrom->s_jxbump = 0;
46595Sbill 		if (op == JBR)
47*630Shenry 			jumpfrom->s_jxfear = JBRFSIZE;
48595Sbill 		else
49*630Shenry 			jumpfrom->s_jxfear = JXXXFSIZE;
50595Sbill 		if (lastnam == 0)
51595Sbill 			yyerror("jxxx destination not a label");
52*630Shenry 		jumpfrom->s_dest = lastnam;
53*630Shenry 		jumpfrom->s_type = dotp->e_xtype;	/*only TEXT or DATA*/
54*630Shenry 		jumpfrom->s_index = dotp-usedot;
55595Sbill 		/*
56595Sbill 		 *	value ALWAYS (ALWAYS!!!) indexes the next instruction
57595Sbill 		 *	after the jump, even in the jump must be exploded
58595Sbill 		 *	(bumped)
59595Sbill 		 */
60*630Shenry 		jumpfrom->s_value = dotp->e_xvalue;
61595Sbill 		njxxx++;
62595Sbill 	} else {/* pass2, resolve */
63595Sbill 		/*
64595Sbill 		 *	READ THIS AFTER LOOKING AT jxxxfix()
65595Sbill 		 */
66595Sbill 		register long		oxvalue;
67595Sbill 		register struct	exp 	*xp;
68595Sbill 		register struct symtab	*tunnel;
69595Sbill 		register struct arg	*aplast;
70595Sbill 
71595Sbill 		aplast = ap + nact - 1;
72*630Shenry 		xp = aplast->a_xp;
73*630Shenry 		if (lastjxxx->s_tag == JXTUNNEL){
74*630Shenry 			lastjxxx->s_tag = JXINACTIVE;
75*630Shenry 			tunnel = lastjxxx->s_dest;
76*630Shenry 			xp->e_xvalue = tunnel->s_value	/*index of instruction following*/
77595Sbill 				    - 3			/* size of brw + word*/
78*630Shenry 				    + ( ( (tunnel->s_jxfear == JBRFSIZE) &&
79*630Shenry 					  (tunnel->s_jxbump == 0))?1:0);
80595Sbill 							/*non bumped branch byteis only 2 back*/
81595Sbill 		}
82*630Shenry 		if (lastjxxx->s_jxbump == 0){	/*wasn't bumped, so is short form*/
83595Sbill 			putins(op, ap, nact);
84595Sbill 		} else {
85595Sbill 			if (op != JBR){	/*branch reverse conditional byte over
86595Sbill 					  branch unconditional word*/
87*630Shenry 				oxvalue = xp->e_xvalue;
88*630Shenry 				xp->e_xvalue = lastjxxx->s_value;
89595Sbill 				putins(op^1, ap, nact);
90*630Shenry 				xp->e_xvalue = oxvalue;
91595Sbill 			}
92595Sbill 			putins(BRW, aplast, 1);
93595Sbill 		}
94595Sbill 	}
95595Sbill }	/*end of ijxout*/
96595Sbill 
97595Sbill jalign(xp, sp)
98595Sbill 	register struct exp *xp;
99595Sbill 	register struct symtab *sp;
100595Sbill {
101595Sbill 	register	int	mask;
102*630Shenry 	if (xp->e_xtype != XABS || xp->e_xvalue < 0 || xp->e_xvalue > 16) {
103595Sbill 		yyerror("Illegal `align' argument");
104595Sbill 		return;
105595Sbill 	}
106595Sbill 	flushfield(NBPW/4);
107595Sbill 	if (passno == 1) {
108*630Shenry 		sp->s_tag = JXALIGN;
109*630Shenry 		sp->s_jxfear = (1 << xp->e_xvalue) - 1;
110*630Shenry 		sp->s_type = dotp->e_xtype;
111*630Shenry 		sp->s_index = dotp-usedot;
112595Sbill 		/*
113595Sbill 		 *	We guess that the align will take up at least one
114595Sbill 		 *	byte in the code output.  We will correct for this
115595Sbill 		 *	initial high guess when we explode (bump) aligns
116595Sbill 		 *	when we fix the jxxxes.  We must do this guess
117595Sbill 		 *	so that the symbol table is sorted correctly
118595Sbill 		 *	and labels declared to fall before the align
119595Sbill 		 *	really get their, instead of guessing zero size
120595Sbill 		 *	and have the label (incorrectly) fall after the jxxx.
121595Sbill 		 *	This is a quirk of our requirement that indices into
122595Sbill 		 *	the code stream point to the next byte following
123595Sbill 		 *	the logical entry in the symbol table
124595Sbill 		 */
125*630Shenry 		dotp->e_xvalue += 1;
126*630Shenry 		sp->s_value = dotp->e_xvalue;
127595Sbill 		njxxx++;
128595Sbill 	} else {
129*630Shenry 		mask = (1 << xp->e_xvalue) - 1;
130*630Shenry 		while (dotp->e_xvalue & mask){
131595Sbill #ifdef UNIX
132595Sbill 			outb(0);
133595Sbill #endif UNIX
134595Sbill #ifdef VMS
135595Sbill 			*vms_obj_ptr++ = -1;
136595Sbill 			*vms_obj_ptr++ = 0;
137*630Shenry 			dotp->e_xvalue += 1;
138595Sbill #endif VMS
139595Sbill 		}
140595Sbill 	}
141595Sbill }
142595Sbill 
143595Sbill /*
144595Sbill  *	Pass 1.5, resolve jxxx instructions and .align in .text
145595Sbill  */
146595Sbill jxxxfix()
147595Sbill {
148595Sbill 	register struct symtab 	*jumpfrom;
149595Sbill 		 struct symtab	**cojumpfrom, *ubjumpfrom;
150595Sbill 	register struct symtab 	*dest;
151595Sbill 	register struct symtab	*intdest;	/*intermediate dest*/
152595Sbill 	register struct symtab	**cointdest, *ubintdest;
153595Sbill 
154595Sbill 	register struct symtab 	*tunnel;
155595Sbill 	 	 int 		displ,nchange;
156595Sbill 		 int		badjxalign;	/*if jump across an align*/
157595Sbill 		 int		stillactives;	/*if still active jxxxes*/
158595Sbill 		 int		segno;		/*current segment number*/
159595Sbill 		 int		topono;		/*which iteration in the topo sort*/
160595Sbill 	register unsigned char	tag;
161595Sbill 	/*
162595Sbill 	 *	consider each segment in turn...
163595Sbill 	 */
164595Sbill 	for (segno = 0; segno < NLOC + NLOC; segno++){
165595Sbill 	    badjxalign = 0;		/*done on a per segment basis*/
166595Sbill 	    /*
167595Sbill 	     *	Do a lazy topological sort.
168595Sbill 	     */
169595Sbill 	    for (topono = 1, nchange = 1; nchange != 0; topono++){
170595Sbill #ifdef DEBUG
171595Sbill 		if (debug)
172595Sbill 			printf("\nSegment %d, topo iteration %d\n",
173595Sbill 				segno, topono);
174595Sbill #endif
175595Sbill 		nchange = 0;
176595Sbill 		stillactives = 0;
177595Sbill 		/*
178595Sbill 		 *	We keep track of one possible tunnel location.
179595Sbill 		 *	A tunnel will eventually be an unconditional
180595Sbill 		 *	branch to the same place that another jxxx
181595Sbill 		 *	will want to branch to.  We will turn a
182595Sbill 		 *	branch conditional/unconditional (word) that would
183595Sbill 		 *	have to get bumped because its destination is too
184595Sbill 		 *	far away, into a branch conditional/unconditional
185595Sbill 		 *	byte to the tunnel branch conditional/unconditional.
186595Sbill 		 *	Of course, the tunnel must branch to the same place
187595Sbill 		 *	as we want to go.
188595Sbill 		 */
189595Sbill 		tunnel = 0;	/*initially, no tunnel*/
190595Sbill 		SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){
191*630Shenry 			tag = jumpfrom->s_tag;
192595Sbill 			if (tag <= IGNOREBOUND)
193595Sbill 				continue;	/*just an ordinary symbol*/
194595Sbill 			if (tag == JXALIGN){
195595Sbill 				tunnel = 0;	/*avoid tunneling across a flex alocation*/
196595Sbill 				continue;	/*we take care of these later*/
197595Sbill 			}
198*630Shenry 			if (   jumpfrom->s_jxfear == JBRFSIZE	/*unconditional*/
199595Sbill 			    || (   tag == JXINACTIVE		/*inactive bumped*/
200*630Shenry 				&& (jumpfrom->s_jxbump != 0)
201595Sbill 			       )
202595Sbill 			   ) tunnel = jumpfrom;
203595Sbill 			if (tag != JXACTIVE)
204595Sbill 				continue;
205*630Shenry 			dest = jumpfrom->s_dest;
206*630Shenry 			if (jumpfrom->s_index != dest->s_index){
207595Sbill 				yyerror("Intersegment jxxx");
208595Sbill 				continue;
209595Sbill 			}
210*630Shenry 			displ = dest->s_value - jumpfrom->s_value;
211595Sbill 			if (displ < MINBYTE || displ > MAXBYTE) {
212595Sbill 				/*
213595Sbill 				 *	This is an immediate lose!
214595Sbill 				 *
215595Sbill 				 *	We first attempt to tunnel
216595Sbill 				 *	by finding an intervening jump that
217595Sbill 				 *	has  the same destination.
218595Sbill 				 *	The tunnel is always the first preceeding
219595Sbill 				 *	jxxx instruction, so the displacement
220595Sbill 				 *	to the tunnel is less than zero, and
221595Sbill 				 *	its relative position will be unaffected
222595Sbill 				 *	by future jxxx expansions.
223595Sbill 				 */
224*630Shenry 				if (    (jumpfrom->s_jxfear > JBRFSIZE)
225595Sbill 				     && (tunnel)
226*630Shenry 				     && (tunnel->s_dest == jumpfrom->s_dest)
227*630Shenry 				     && (tunnel->s_index == jumpfrom->s_index)
228*630Shenry 				     && (tunnel->s_value - jumpfrom->s_value >=
229595Sbill 						MINBYTE + JXXXFSIZE)
230595Sbill 				   ) {
231595Sbill 						/*
232595Sbill 						 *	tunnelling is OK
233595Sbill 						 */
234*630Shenry 						jumpfrom->s_dest = tunnel;
235595Sbill 						/*
236595Sbill 						 * no bumping needed, this
237595Sbill 						 * is now effectively inactive
238595Sbill 						 * but must be remembered
239595Sbill 						 */
240*630Shenry 						jumpfrom->s_tag = JXTUNNEL;
241595Sbill #ifdef DEBUG
242595Sbill 						if(debug)
243595Sbill 						printf("Tunnel from %s from line %d\n",
244*630Shenry 							jumpfrom->s_name, lineno);
245595Sbill #endif
246595Sbill 						continue;
247595Sbill 				} else {	/*tunneling not possible*/
248595Sbill 					/*
249595Sbill 					 *	since this will be turned
250595Sbill 					 *	into a bumped jump, we can
251595Sbill 					 *	use the unconditional jump
252595Sbill 					 *	as a tunnel
253595Sbill 					 */
254595Sbill 					tunnel = jumpfrom;
255*630Shenry 					jumpfrom->s_tag = JXNOTYET;
256595Sbill 					++nchange;
257595Sbill 					continue;
258595Sbill 				}
259595Sbill 			}	/*end of immediate lose*/
260595Sbill 			/*
261595Sbill 			 *	Do a forward search for an intervening jxxx
262595Sbill 			 */
263595Sbill 			if (displ >= 0) {
264595Sbill 				SEGITERATE(segno, cojumpfrom + 1,0,cointdest,
265595Sbill 						intdest, ubintdest, ++){
266*630Shenry 					if (intdest->s_value > dest->s_value)
267595Sbill 						break; /* beyond destination */
268*630Shenry 					if (intdest->s_tag <= JXQUESTIONABLE)
269595Sbill 						continue;	/*frozen solid*/
270*630Shenry 					if (intdest->s_tag == JXALIGN){
271*630Shenry 						jumpfrom->s_jxoveralign = 1;
272595Sbill 						badjxalign++;
273595Sbill 					}
274595Sbill 					/*
275595Sbill 					 *	we assume the worst case
276595Sbill 					 *	for unfrozen jxxxxes
277595Sbill 					 */
278*630Shenry 					displ += intdest->s_jxfear;
279595Sbill 				}
280595Sbill 				if (displ <= MAXBYTE){
281595Sbill 					/*
282595Sbill 					 *	the worst possible conditions
283595Sbill 					 *	can't hurt us, so forget about
284595Sbill 					 *	this jump
285595Sbill 					 */
286*630Shenry 					jumpfrom->s_tag = JXINACTIVE;
287595Sbill 				} else {
288595Sbill 					stillactives++;
289595Sbill 				}
290595Sbill 			} else {
291595Sbill 			/*
292595Sbill 			 *	backward search for intervening jxxx
293595Sbill 			 */
294595Sbill 				SEGITERATE(segno, cojumpfrom - 1,1,cointdest,
295595Sbill 				  intdest, ubintdest, --){
296*630Shenry 					if (intdest->s_value <= dest->s_value)
297595Sbill 						break; /* beyond destination */
298*630Shenry 					if (intdest->s_tag <= JXQUESTIONABLE)
299595Sbill 						continue;	/*frozen solid*/
300*630Shenry 					if (intdest->s_tag == JXALIGN){
301*630Shenry 						jumpfrom->s_jxoveralign = 1;
302595Sbill 						badjxalign++;
303595Sbill 					}
304*630Shenry 					displ -= intdest->s_jxfear;
305595Sbill 				}
306595Sbill 				if (displ >= MINBYTE) {
307*630Shenry 					jumpfrom->s_tag = JXINACTIVE;
308595Sbill 				} else {
309595Sbill 					stillactives++;
310595Sbill 				}
311595Sbill 			}	/*end of backwards search*/
312595Sbill 		}	/*end of iterating through all symbols in this seg*/
313595Sbill 
314595Sbill 		if (nchange == 0) {
315595Sbill 			/*
316595Sbill 			 *	Now, if there are still active jxxx entries,
317595Sbill 			 *	we are partially deadlocked.  We can leave
318595Sbill 			 *	these jxxx entries in their assumed short jump
319595Sbill 			 *	form, as all initial displacement calcualtions
320595Sbill 			 *	are hanging on unresolved jxxx instructions
321595Sbill 			 *	that might explode into a long form, causing
322595Sbill 			 *	other jxxxes jumping across the first set of
323595Sbill 			 *	jxxxes to explode, etc.
324595Sbill 			 *	However, if a jxxx jumps across a .align,
325595Sbill 			 *	we assume the worst for the deadlock cycle,
326595Sbill 			 *	and resolve all of them towards the long
327595Sbill 			 *	jump.
328595Sbill 			 *	Currently, the C compiler does not produce
329595Sbill 			 *	jumps across aligns, as aligns are only used
330595Sbill 			 *	in data segments, or in text segments to align
331595Sbill 			 *	functions.
332595Sbill 			 */
333595Sbill 			if (stillactives){
334595Sbill 				SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom,
335595Sbill 				    ubjumpfrom, ++){
336*630Shenry 					if (jumpfrom->s_tag == JXACTIVE){
337*630Shenry 						jumpfrom->s_tag =
338595Sbill 						  badjxalign?JXNOTYET:JXINACTIVE;
339595Sbill 					}
340595Sbill 				}
341595Sbill 				if (badjxalign){
342595Sbill 					jxxxbump(segno, (struct symtab **)0);
343595Sbill 				}
344595Sbill 			}
345595Sbill 			/*
346595Sbill 			 *	Handle  all of the .align s
347595Sbill 			 */
348595Sbill 			SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom,
349595Sbill 			   ubjumpfrom, ++){
350*630Shenry 			    if (jumpfrom->s_tag == JXALIGN){
351595Sbill 				/*
352595Sbill 				 *	Predict the true displacement
353595Sbill 				 *	needed, irregardless of the
354595Sbill 				 *	fact that we guessed 1
355595Sbill 				 */
356*630Shenry 				displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear;
357595Sbill 				if (displ == 0){	/*no virtual displacement*/
358*630Shenry 					jumpfrom->s_jxfear = -1;
359595Sbill 				} else {
360*630Shenry 					jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ;
361595Sbill 					/*
362*630Shenry 					 *	assert jumpfrom->s_jxfear > 0
363595Sbill 					 */
364*630Shenry 					if (jumpfrom->s_jxfear == 1){
365595Sbill 						/*our prediction was correct*/
366595Sbill 						continue;
367595Sbill 					}
368595Sbill 					/*
369*630Shenry 					 *	assert jumpfrom->s_jxfear > 1
370595Sbill 					 */
371*630Shenry 					jumpfrom->s_jxfear -= 1;	/*correct guess*/
372595Sbill 				}
373595Sbill 				/*
374*630Shenry 				 *	assert jumpfrom->s_jxfear = -1, +1...2**n-1
375595Sbill 				 */
376*630Shenry 				jumpfrom->s_tag = JXNOTYET;	/*signal*/
377595Sbill 				jxxxbump(segno, cojumpfrom);
378*630Shenry 				jumpfrom->s_tag = JXINACTIVE;
379595Sbill 				/*
380595Sbill 				 *	Assert jxfrom->jxvalue indexes the first
381595Sbill 				 *	code byte after the added bytes, and
382595Sbill 				 *	has n low order zeroes.
383595Sbill 				 */
384595Sbill 			  }
385595Sbill 			}	/*end of walking through each segment*/
386595Sbill 	    	}	/*end of no changes */
387595Sbill 		else {	/*changes, and still have to try another pass*/
388595Sbill 			jxxxbump(segno, (struct symtab **)0);
389595Sbill 		}
390595Sbill 	   }	/*end of doing the topologic sort*/
391595Sbill 	}	/*end of iterating through all segments*/
392595Sbill }	/*end of jxxxfix*/
393595Sbill 
394595Sbill /*
395595Sbill  *	Go through the symbols in a given segment number,
396595Sbill  *	and see which entries are jxxx entries that have
397595Sbill  *	been logically "exploded" (expanded), but for which
398595Sbill  *	the value of textually following symbols has not been
399595Sbill  *	increased
400595Sbill  */
401595Sbill 
402595Sbill jxxxbump(segno, starthint)
403595Sbill 	int	segno;
404595Sbill 	struct	symtab **starthint;
405595Sbill {
406595Sbill 	register	struct	symtab	**cosp, *sp;
407595Sbill 	register	struct	symtab		*ub;
408595Sbill 	register	int	cum_bump;
409595Sbill 	register	unsigned	char	tag;
410595Sbill 
411595Sbill 	cum_bump = 0;
412595Sbill 	SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){
413*630Shenry 		tag = sp->s_tag;
414595Sbill 		if (tag == JXNOTYET){
415595Sbill #ifdef DEBUG
416595Sbill 			if (debug){
417*630Shenry 			if (sp->s_dest != 0)
418595Sbill 				printf("Explode jump to %s on line %d\n",
419*630Shenry 					sp->s_dest->s_name, lineno);
420595Sbill 			else
421595Sbill 				printf("Explode an align!\n");
422595Sbill 			}
423595Sbill #endif
424*630Shenry 			sp->s_tag = JXINACTIVE;
425*630Shenry 			sp->s_jxbump = 1;
426*630Shenry 			cum_bump += sp->s_jxfear;
427595Sbill 		}
428595Sbill 		/*
429595Sbill 		 *	Only bump labels and jxxxes. Ignored entries can
430595Sbill 		 *	be incremented, as they are thrown away later on.
431595Sbill 		 *	Stabds are given their final value in the second
432595Sbill 		 *	pass.
433595Sbill 		 */
434595Sbill 		if (tag >= OKTOBUMP)	/*only bump labels and jxxxes and floating stabs*/
435*630Shenry 			sp->s_value += cum_bump;
436595Sbill 	}
437*630Shenry 	usedot[segno].e_xvalue += cum_bump;
438595Sbill }
439