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