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